mirror of https://github.com/swig/swig
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:
parent
db5e37a1d7
commit
1b63af0f2c
|
@ -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
|
||||
|
|
|
@ -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 <std_unique_ptr.i>
|
||||
|
@ -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 <std_auto_ptr.i>
|
||||
|
@ -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>
|
||||
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue