diff --git a/CHANGES.current b/CHANGES.current index d06c0736b..1d99fd0fc 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -7,6 +7,16 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/ Version 4.1.0 (in progress) =========================== +2022-08-31: wsfulton + #999 Improve move semantics when using rvalue references. + The SWIGTYPE && input typemaps now assume the object has been moved. + + These typemaps have been changed assuming that after the function call, + the rvalue reference parameter has been moved. The parameter's proxy class + that owns the C++ object thus has the underlying pointer set to null + so that the (moved from, but still valid) C++ object cannot be used again + and the the object is additionally deleted. + 2022-08-28: wsfulton [Octave] SWIG now marshalls a C/C++ NULL pointer into the null matrix, []. SWIG has always marshalled the null matrix into a NULL pointer; this remains diff --git a/Doc/Manual/CPlusPlus11.html b/Doc/Manual/CPlusPlus11.html index 7618b6dbe..ca8d3d575 100644 --- a/Doc/Manual/CPlusPlus11.html +++ b/Doc/Manual/CPlusPlus11.html @@ -98,6 +98,7 @@ class MyClass { ... std::vector<int> numbers; public: + MyClass() : numbers() {} MyClass(MyClass &&other) : numbers(std::move(other.numbers)) {} MyClass & operator=(MyClass &&other) { numbers = std::move(other.numbers); @@ -107,8 +108,8 @@ public:
-Rvalue references are designed for C++ temporaries and so are not very useful when used from non-C++ target languages. -Generally you would just ignore them via %ignore before parsing the class. +Rvalue references are designed for C++ temporaries and are not particularly useful when used from non-C++ target languages. +You could just ignore them via %ignore before parsing the class. For example, ignore the move constructor:
@@ -117,7 +118,39 @@ For example, ignore the move constructor:-The plan is to ignore move constructors by default in a future version of SWIG. Note that both normal assignment operators as well as move assignment operators are ignored by default in most target languages with the following warning: +However, if you do wrap a function/contructor with an rvalue reference and pass a proxy class to it, SWIG will assume that after the call, the rvalue reference parameter will have been 'moved'. +The proxy class passed as the rvalue reference, will own the underlying C++ object up until it is used as an rvalue reference parameter. +Afterwards, the proxy class will have the underlying C++ pointer set to the nullptr so that the proxy class instance cannot be used again and the underlying (moved from) C++ object will be deleted after the function/constructor call has returned. +
+ ++In this way, the SWIG proxy class works much like an exclusively owned smart pointer (think of std::unique_ptr), passing ownership to the called C++ function/constructor. +Let's consider an example in Java using the wrapped proxy class from above: +
+ ++MyClass mc = new MyClass(); +MyClass mc1 = new MyClass(mc); // move constructor +MyClass mc2 = new MyClass(mc); // move constructor fails +
+The second call to the move constructor will fail as the mc proxy instance has been moved. +Each target language handles the moved proxy class slightly differently, but typically you'll get an exception such as in Java: +
+ ++Exception in thread "main" java.lang.RuntimeException: Cannot release ownership as memory is not owned + at MyClass.swigRelease(MyClass.java:27) + at MyClass.+(MyClass.java:55) + at runme.main(runme.java:18) +
+Note that both normal copy assignment operators as well as move assignment operators are ignored by default in the target languages with the following warning:
+Using a %rename will remove the warning, however, a %rename makes the move constructor available from the target language: +
++%rename(MoveAssign) MyClass::operator=(MyClass &&); +
+You can then use the move assignment operator, but like the move constructor example above, you cannot use +a proxy class once it has been moved: +
+ ++MyClass mc = new MyClass(); +MyClass mc2 = mc.MoveAssign(mc); +MyClass mc3 = mc.MoveAssign(mc); // Use of mc again will fail +
+Compatibility note: +SWIG-4.1.0 changed the way that rvalue references were handled and implemented typemaps assuming that the +proxy class would transfer ownership of the underlying C++ object when a function/constructor with an rvalue reference parameter was called. +
+