Swig behavior for methods that accept rvalue reference as a parameter

Rinat Veliakhmedov :

Swig documentation specifies that it intentionally ignores move constructors. However it does not specify what it does with methods that accept rvlaue reference, for example:

class AAA {
public:
    AAA() {}; // generates java code
    AAA(const AAA& a) {}; // generates java code
    AAA(AAA&& a) {}; // ignored by swig, no java code generated
    virtual void move(const std::string& str); // generates java code
    virtual void move(std::string&& str); // also generates java code, but accepts SWIGTYPE_p_std__string as a parameter instead of String
};

Would these methods behave differently? Is there a go-to way of working with rvalue parameters in swig? Or should I just not use them?

Flexo :

Generally for well written C++ code you'd expect the same behavior of two overloaded functions or constructors to be equivalent, with the caveat that the rvalue reference variant will most likely be destructive to its input.

So for making an interface in another language, which probably doesn't really have any neat 1:1 mapping to the concept that rvalues are trying to express then the vast majority of the time the right answer is to simply ignore these overloads. Internally in some cases the SWIG generated wrappers might end up using these overloads, or could be written to do so with some effort on your part, but it's just an optimization. And if you're jumping across a JNI boundary then that's probably unlikely to be your biggest performance bottleneck. (Measure it to be sure before doing anything).

In some language (e.g. Python, Lua?) you might be tempted to use the fact that your objects are reference counted to your advantage and (transparently to these languages) write a typemap that picks which overload to use based on if we're the only ones holding a reference to an object still. I'd argue that even this case is wrong (and also premature optimization) though because:

  1. There's a race condition around weak references if the language supports such a construct. It's hard to spot and avoid this.
  2. Even though you have only one reference to your (e.g.) Python object there could still be multiple references to the same C++ object, for instance:

    struct a {};
    a& blah() {
      static a a;
      return a;
    }
    

    With

    import test
    a=test.blah()
    b=test.blah()
    c=test.blah()
    

    Has both a,b, and c only having 1 reference, yet moving those would clearly be wrong. And it's almost impossible to to prove when it would be safe.

So what I'm saying is: ignore them unless you have no choice. Sometimes you might come across cases where the only option is to call a function that takes an rvalue reference. You can wrap those functions, but it needs to be done on a case by case basis as you need to understand the semantics of the function/constructor being wrapped.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=154690&siteId=1