diff --git a/Doc/Manual/Go.html b/Doc/Manual/Go.html index 175f22f26..0a413b25a 100644 --- a/Doc/Manual/Go.html +++ b/Doc/Manual/Go.html @@ -436,34 +436,119 @@ for this by calling the Swigcptr() method.
-Calling NewClassName for some C++ class ClassName -will allocate memory using the C++ memory allocator. This memory will -not be automatically freed by Go's garbage collector as the object ownership is -not tracked. When you are done with the C++ object you must free it manually -using DeleteClassName. -
- -
-A common technique is to store the C++ object into a Go object, and
-use the Go function runtime.SetFinalizer to free the C++ object when
-the Go object is freed. It is strongly recommended to read the
-runtime.SetFinalizer
-documentation before using this technique to understand its limitations.
-For example, if the SWIG package is imported as "wrap":
+Calling NewClassName for a C++ class ClassName will allocate
+memory using the C++ memory allocator. This memory will not be automatically
+freed by Go's garbage collector as the object ownership is not tracked. When
+you are done with the C++ object you must free it using
+DeleteClassName.
+
+The most Go idiomatic way to manage the memory for some C++ class is to call
+NewClassName followed by a
+defer of
+the DeleteClassName call. Using defer ensures that the memory
+of the C++ object is freed as soon as the function containing the defer
+statement returns. Furthemore defer works great for short-lived
+objects and fits nicely C++'s RAII idiom. Example:
+func UseClassName(...) ... {
+ o := NewClassName(...)
+ defer DeleteClassName(o)
+ // Use the ClassName object
+ return ...
+}
+
++With increasing complexity, especially complex C++ object hierarchies, the +correct placement of defer statements becomes harder and harder as C++ +objects need to be freed in the correct order. This problem can be eased by +keeping a C++ object function local so that it is only available to the function +that creates a C++ object and functions called by this function. Example: +
+
+func WithClassName(constructor args, f func(ClassName, ...interface{}) error, data ...interface{}) error {
+ o := NewClassName(constructor args)
+ defer DeleteClassName(o)
+ return f(o, data...)
+}
+
+func UseClassName(o ClassName, data ...interface{}) (err error) {
+ // Use the ClassName object and additional data and return error.
+}
+
+func main() {
+ WithClassName(constructor args, UseClassName, additional data)
+}
+
+
+Using defer has limitations though, especially when it comes to
+long-lived C++ objects whichs lifetimes are hard to predict. For such C++
+objects a common technique is to store the C++ object into a Go object, and to
+use the Go function runtime.SetFinalizer to add a finalizer which frees
+the C++ object when the Go object is freed. It is strongly recommended to read
+the runtime.SetFinalizer
+ documentation before using this technique to understand the
+runtime.SetFinalizer limitations.
+
+Common pitfalls with runtime.SetFinalizer are:
+
+runtime.SetFinalizer Example: +
+
+import (
+ "runtime"
+ "wrap" // SWIG generated wrapper code
+)
+
type GoClassName struct {
- w wrap.ClassName
+ wcn wrap.ClassName
}
func NewGoClassName() *GoClassName {
- r := &GoClassName{wrap.NewClassName()}
- runtime.SetFinalizer(r,
- func(r *GoClassName) {
- wrap.DeleteClassName(r.w)
- })
- return r
+ o := &GoClassName{wcn: wrap.NewClassName()}
+ runtime.SetFinalizer(o, deleteGoClassName)
+ return o
+}
+
+func deleteGoClassName(o *GoClassName) {
+ // Runs typically in a different OS thread!
+ wrap.DeleteClassName(o.wcn)
+ o.wcn = nil
+}
+
+func (o *GoClassName) Close() {
+ // If the C++ object has a Close method.
+ o.wcn.Close()
+
+ // If the GoClassName object is no longer in an usable state.
+ runtime.SetFinalizer(o, nil) // Remove finalizer.
+ deleteGoClassName() // Free the C++ object.
}