std::unique_ptr std::auto_ptr tidyup

Add docs on additional support
Additional testing for invalid usage for parameter inputs
This commit is contained in:
William S Fulton 2022-07-19 08:57:47 +01:00
parent db5e37a1d7
commit 1b63af0f2c
10 changed files with 107 additions and 22 deletions

View File

@ -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

View File

@ -2055,13 +2055,9 @@ equivalent <tt>%shared_ptr(T)</tt> macro covered in the previous section.
</p>
<p>
Note that the support provided is limited to returning this smart pointer from a function.
Any other use of <tt>std::auto_ptr</tt> is not directly provided yet.
Example usage of a <tt>std::unique_ptr</tt> being returned from a function is shown below.
</p>
<p>
Example usage would be
</p>
<div class="code">
<pre>
%include &lt;std_unique_ptr.i&gt;
@ -2113,12 +2109,67 @@ Note that the implementation is quite different to the <tt>std::shared_ptr</tt>
where the proxy class manages the underlying C++ memory as a pointer to a shared_ptr instead of a plain raw pointer.
</p>
<p>
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.
</p>
<p>
Consider expanding the example above with a function that takes a <tt>std::unique_ptr</tt> as follows:
</p>
<div class="code">
<pre>
void take(std::unique_ptr<Klass>);
</pre>
</div>
<p>
and use from C#:
</p>
<div class="targetlang">
<pre>
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
</pre>
</div>
<p>
Attempts to use <tt>k</tt> after the ownership has been passed into the <tt>take</tt> 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 <tt>take</tt> 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.
</p>
<p>
Attempts to pass ownership from a proxy class to a <tt>std::unique</tt> parameter more than once will result
in a "Cannot release ownership as memory is not owned" exception. For example, if <tt>example.take(k)</tt> in the example above is called twice.
</p>
<p>
<b>Compatibility note:</b> Support for <tt>std::unique_ptr</tt> was added in SWIG-4.1.0.
</p>
<H3><a name="Library_std_auto_ptr">12.4.6 auto_ptr smart pointer</a></H3>
<p>
While <tt>std::auto_ptr</tt> 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 <tt>std::unique_ptr</tt>.
</p>
<p>
@ -2133,13 +2184,9 @@ the previous two sections.
</p>
<p>
Note that the support provided is limited to returning this smart pointer from a function.
Any other use of <tt>std::auto_ptr</tt> is not directly provided.
Example usage of a <tt>std::auto_ptr</tt> being returned from a function is shown below.
</p>
<p>
Example usage would be
</p>
<div class="code">
<pre>
%include &lt;std_auto_ptr.i&gt;
@ -2181,6 +2228,10 @@ The implementation simply calls <tt>std::auto_ptr::release()</tt> to obtain the
That is, it works the same way covered in the previous section for <tt>std::unique_ptr</tt>.
</p>
<p>
Input parameters also work the same way as <tt>std::unique_ptr</tt> covered in the previous section.
</p>
<H2><a name="Library_nn16">12.5 Utility Libraries</a></H2>

View File

@ -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");

View File

@ -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");

View File

@ -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)

View File

@ -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)

View File

@ -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")

View File

@ -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")

View File

@ -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)

View File

@ -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)