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.
 }