diff --git a/CHANGES.current b/CHANGES.current index e312abaaa..3ed3a94a5 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -7,6 +7,14 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/ Version 4.1.0 (in progress) =========================== +2022-07-19: wsfulton + #692 [C#, Java, Perl, Python, Ruby] std::unique_ptr and std::auto_ptr typemaps + provided for inputs types in std_unique_ptr.i and std_auto_ptr.i. + + Now these smart pointers can be used as input parameters to functions. A proxy + class instance transfers memory ownership of the underlying C++ object from the + proxy class to a smart pointer instance passed to the wrapped function. + 2022-07-12: wsfulton Performance optimisation for parameters passed by value that are C++11 movable. The C++ wrappers create a temporary variable for a parameter to be passed to a diff --git a/Doc/Manual/Library.html b/Doc/Manual/Library.html index b18ecc957..7dc649c16 100644 --- a/Doc/Manual/Library.html +++ b/Doc/Manual/Library.html @@ -2055,13 +2055,9 @@ equivalent %shared_ptr(T) macro covered in the previous section.

-Note that the support provided is limited to returning this smart pointer from a function. -Any other use of std::auto_ptr is not directly provided yet. +Example usage of a std::unique_ptr being returned from a function is shown below.

-

-Example usage would be -

 %include <std_unique_ptr.i>
@@ -2113,12 +2109,67 @@ Note that the implementation is quite different to the std::shared_ptr
 where the proxy class manages the underlying C++ memory as a pointer to a shared_ptr instead of a plain raw pointer.
 

+

+A possibly less common usage of this smart pointer is as a parameter to a function. +When used like this it indicates that memory usage of the object pointed to by the underlying pointer +is transferred to the function being called. +The code that SWIG generates assumes this happens. +First, it is assumed that a proxy class already owns the underlying C++ object and is used to pass the object to the C++ function being called. +Second, the ownership is transferred from the proxy class to the C++ function being called and +lifetime is then controlled by the function. +Finally, it is assumed the lifetime of the object may not last beyond returning from the C++ function +and hence the proxy class can no longer be used. +

+ +

+Consider expanding the example above with a function that takes a std::unique_ptr as follows: +

+ +
+
+void take(std::unique_ptr);
+
+
+ +

+and use from C#: +

+ +
+
+Klass k = Klass.Create(17); // create an instance of Klass any way you like
+int value = k.getValue();   // ok
+example.take(k);            // memory ownership passes from C# layer to C++ layer
+int v = k.getValue();       // don't do this - invalid use of k
+
+
+ +

+Attempts to use k after the ownership has been passed into the take function +should not be attempted. +The implementation sets the proxy class to an invalid state by setting the class's underlying +C++ pointer to null after the return from the take function. +Subsequent use of an invalid proxy class instance is very much dependent on the implementation +in the target language and ranges from a segfault to giving a nice error. +Consider implementing additional checks via the 'check' typemap. +

+ +

+Attempts to pass ownership from a proxy class to a std::unique parameter more than once will result +in a "Cannot release ownership as memory is not owned" exception. For example, if example.take(k) in the example above is called twice. +

+ +

+Compatibility note: Support for std::unique_ptr was added in SWIG-4.1.0. +

+

12.4.6 auto_ptr smart pointer

While std::auto_ptr is deprecated in C++11, some existing code may -still be using it, so SWIG provides limited support for this class by some target languages. +still be using it. SWIG provides support for this class which is nearly identical +to std::unique_ptr.

@@ -2133,13 +2184,9 @@ the previous two sections.

-Note that the support provided is limited to returning this smart pointer from a function. -Any other use of std::auto_ptr is not directly provided. +Example usage of a std::auto_ptr being returned from a function is shown below.

-

-Example usage would be -

 %include <std_auto_ptr.i>
@@ -2181,6 +2228,10 @@ The implementation simply calls std::auto_ptr::release() to obtain the
 That is, it works the same way covered in the previous section for std::unique_ptr.
 

+

+Input parameters also work the same way as std::unique_ptr covered in the previous section. +

+

12.5 Utility Libraries

diff --git a/Examples/test-suite/csharp/cpp11_std_unique_ptr_runme.cs b/Examples/test-suite/csharp/cpp11_std_unique_ptr_runme.cs index 5b730aa05..09c6ec0af 100644 --- a/Examples/test-suite/csharp/cpp11_std_unique_ptr_runme.cs +++ b/Examples/test-suite/csharp/cpp11_std_unique_ptr_runme.cs @@ -41,7 +41,9 @@ public class cpp11_std_unique_ptr_runme { bool exception_thrown = false; try { cpp11_std_unique_ptr.takeKlassUniquePtr(kin); - } catch (ApplicationException) { + } catch (ApplicationException e) { + if (!e.Message.Contains("Cannot release ownership as memory is not owned")) + throw new ApplicationException("incorrect exception message"); exception_thrown = true; } if (!exception_thrown) @@ -52,10 +54,12 @@ public class cpp11_std_unique_ptr_runme { using (Klass kin = new Klass("KlassInput")) { bool exception_thrown = false; try { - Klass notowned = cpp11_std_unique_ptr.get_not_owned_ptr(kin); - cpp11_std_unique_ptr.takeKlassUniquePtr(notowned); - } catch (ApplicationException) { - exception_thrown = true; + Klass notowned = cpp11_std_unique_ptr.get_not_owned_ptr(kin); + cpp11_std_unique_ptr.takeKlassUniquePtr(notowned); + } catch (ApplicationException e) { + if (!e.Message.Contains("Cannot release ownership as memory is not owned")) + throw new ApplicationException("incorrect exception message"); + exception_thrown = true; } if (!exception_thrown) throw new ApplicationException("Should have thrown 'Cannot release ownership as memory is not owned' error"); diff --git a/Examples/test-suite/csharp/li_std_auto_ptr_runme.cs b/Examples/test-suite/csharp/li_std_auto_ptr_runme.cs index b804e7ead..b5ff1fd29 100644 --- a/Examples/test-suite/csharp/li_std_auto_ptr_runme.cs +++ b/Examples/test-suite/csharp/li_std_auto_ptr_runme.cs @@ -41,7 +41,9 @@ public class li_std_auto_ptr_runme { bool exception_thrown = false; try { li_std_auto_ptr.takeKlassAutoPtr(kin); - } catch (ApplicationException) { + } catch (ApplicationException e) { + if (!e.Message.Contains("Cannot release ownership as memory is not owned")) + throw new ApplicationException("incorrect exception message"); exception_thrown = true; } if (!exception_thrown) @@ -52,10 +54,12 @@ public class li_std_auto_ptr_runme { using (Klass kin = new Klass("KlassInput")) { bool exception_thrown = false; try { - Klass notowned = li_std_auto_ptr.get_not_owned_ptr(kin); - li_std_auto_ptr.takeKlassAutoPtr(notowned); - } catch (ApplicationException) { - exception_thrown = true; + Klass notowned = li_std_auto_ptr.get_not_owned_ptr(kin); + li_std_auto_ptr.takeKlassAutoPtr(notowned); + } catch (ApplicationException e) { + if (!e.Message.Contains("Cannot release ownership as memory is not owned")) + throw new ApplicationException("incorrect exception message"); + exception_thrown = true; } if (!exception_thrown) throw new ApplicationException("Should have thrown 'Cannot release ownership as memory is not owned' error"); diff --git a/Examples/test-suite/java/cpp11_std_unique_ptr_runme.java b/Examples/test-suite/java/cpp11_std_unique_ptr_runme.java index 14c117206..36a9c03fc 100644 --- a/Examples/test-suite/java/cpp11_std_unique_ptr_runme.java +++ b/Examples/test-suite/java/cpp11_std_unique_ptr_runme.java @@ -55,6 +55,8 @@ public class cpp11_std_unique_ptr_runme { try { cpp11_std_unique_ptr.takeKlassUniquePtr(kin); } catch (RuntimeException e) { + if (!e.getMessage().contains("Cannot release ownership as memory is not owned")) + throw new RuntimeException("incorrect exception message"); exception_thrown = true; } if (!exception_thrown) @@ -70,6 +72,8 @@ public class cpp11_std_unique_ptr_runme { Klass notowned = cpp11_std_unique_ptr.get_not_owned_ptr(kin); cpp11_std_unique_ptr.takeKlassUniquePtr(notowned); } catch (RuntimeException e) { + if (!e.getMessage().contains("Cannot release ownership as memory is not owned")) + throw new RuntimeException("incorrect exception message"); exception_thrown = true; } if (!exception_thrown) diff --git a/Examples/test-suite/java/li_std_auto_ptr_runme.java b/Examples/test-suite/java/li_std_auto_ptr_runme.java index 40957e974..daec84dc0 100644 --- a/Examples/test-suite/java/li_std_auto_ptr_runme.java +++ b/Examples/test-suite/java/li_std_auto_ptr_runme.java @@ -55,6 +55,8 @@ public class li_std_auto_ptr_runme { try { li_std_auto_ptr.takeKlassAutoPtr(kin); } catch (RuntimeException e) { + if (!e.getMessage().contains("Cannot release ownership as memory is not owned")) + throw new RuntimeException("incorrect exception message"); exception_thrown = true; } if (!exception_thrown) @@ -70,6 +72,8 @@ public class li_std_auto_ptr_runme { Klass notowned = li_std_auto_ptr.get_not_owned_ptr(kin); li_std_auto_ptr.takeKlassAutoPtr(notowned); } catch (RuntimeException e) { + if (!e.getMessage().contains("Cannot release ownership as memory is not owned")) + throw new RuntimeException("incorrect exception message"); exception_thrown = true; } if (!exception_thrown) diff --git a/Examples/test-suite/python/cpp11_std_unique_ptr_runme.py b/Examples/test-suite/python/cpp11_std_unique_ptr_runme.py index d102ebcd8..d317754b4 100644 --- a/Examples/test-suite/python/cpp11_std_unique_ptr_runme.py +++ b/Examples/test-suite/python/cpp11_std_unique_ptr_runme.py @@ -33,6 +33,8 @@ exception_thrown = False try: s = takeKlassUniquePtr(kin) except RuntimeError as e: + if "cannot release ownership as memory is not owned" not in str(e): + raise RuntimeError("incorrect exception message"); exception_thrown = True if not exception_thrown: raise RuntimeError("double usage of takeKlassUniquePtr should have been an error") diff --git a/Examples/test-suite/python/li_std_auto_ptr_runme.py b/Examples/test-suite/python/li_std_auto_ptr_runme.py index 3f1d392ea..c1df7eb76 100644 --- a/Examples/test-suite/python/li_std_auto_ptr_runme.py +++ b/Examples/test-suite/python/li_std_auto_ptr_runme.py @@ -33,6 +33,8 @@ exception_thrown = False try: s = takeKlassAutoPtr(kin) except RuntimeError as e: + if "cannot release ownership as memory is not owned" not in str(e): + raise RuntimeError("incorrect exception message"); exception_thrown = True if not exception_thrown: raise RuntimeError("double usage of takeKlassAutoPtr should have been an error") diff --git a/Examples/test-suite/ruby/cpp11_std_unique_ptr_runme.rb b/Examples/test-suite/ruby/cpp11_std_unique_ptr_runme.rb index ed9138bcd..83bac5f1b 100644 --- a/Examples/test-suite/ruby/cpp11_std_unique_ptr_runme.rb +++ b/Examples/test-suite/ruby/cpp11_std_unique_ptr_runme.rb @@ -73,7 +73,10 @@ exception_thrown = false begin notowned = Cpp11_std_unique_ptr::get_not_owned_ptr(kin) Cpp11_std_unique_ptr::takeKlassUniquePtr(notowned) -rescue RuntimeError +rescue RuntimeError => e + if (!e.to_s.include? "cannot release ownership as memory is not owned") + raise RuntimeError, "incorrect exception message" + end exception_thrown = true end if (!exception_thrown) diff --git a/Examples/test-suite/ruby/li_std_auto_ptr_runme.rb b/Examples/test-suite/ruby/li_std_auto_ptr_runme.rb index 14e0bd9d4..6562d8d84 100644 --- a/Examples/test-suite/ruby/li_std_auto_ptr_runme.rb +++ b/Examples/test-suite/ruby/li_std_auto_ptr_runme.rb @@ -74,6 +74,9 @@ begin notowned = Li_std_auto_ptr::get_not_owned_ptr(kin) Li_std_auto_ptr::takeKlassAutoPtr(notowned) rescue RuntimeError + if (!e.to_s.include? "cannot release ownership as memory is not owned") + raise RuntimeError, "incorrect exception message" + end exception_thrown = true end if (!exception_thrown)