Skip to content
Li Shengqiu edited this page Mar 27, 2017 · 1 revision

Go is a language with GC, while C++ is not - this makes memory management a bit complicated. For now, wxGo cannot fully automatically handle this issue, but it can be easily done with users' help.

Allocation and Deallocation of wx-Objects

Using wx.NewCLASS and wx.DeleteCLASS

wx-Objects can be allocated and initialized using wx.NewCLASS, for example you can get a wxSizer object by calling wx.NewSizer. All wx.NewCLASS functions will allocate memory on C++ side (on heap), thus it will not be tracked by Go's garbage collector. So you have to free the memory your self, by calling wx.DeleteCLASS(e.g wx.DeleteSizer).

However, a wxSizer is usually in the GUI hierarchy, which means it will be taken own by other object. For example,

dlg := wx.NewDialog(...)
bSizer := wx.NewBoxSizer(wx.VERTICAL)
dlg.SetSizer(bSizer)  // dlg will own bSizer

When dlg is destroyed, bSizer will automatically destroyed by dlg. So we don't have to call wx.DeleteSizer to free it.

Using wx.NewCLASST

In fact, everything goes well with wx.NewCLASS and wx.DeleteCLASS - we use wx.NewCLASS to get an object, and use wx.DeleteCLASS to destroy one when needed. However, it can be a little annoying in some cases:

// In C++, we can write: `dlg.SetSize(wxSize(400, 400))` with no problem.
// In Go, we have to:

size := wx.NewSize(400, 400)  // wxSize* size = new wxSize(400, 400);
dlg.SetSize(size)             // dlg.SetSize(*size);
wx.DeleteSize(size)           // delete size;

// What is more annoying:
// In C++: wxAuiPaneInfo().Name("tb1").Caption("Big Toolbar").ToolbarPane().Top()
// In Go:

wx.NewAuiPaneInfo().Name("tb1").Caption("Big Toolbar").ToolbarPane().Top()
// Memory leaks!!

To make it easier, every object have another NewCLASST function that can be used: the trailing T represents for "tracked", that means the wx-object will be tracked by Go's GC. So we can safely write the following code:

dlg.SetSize(wx.NewSize(400, 400))
paneInfo := wx.NewAuiPaneInfoT().Name("tb1").Caption("Big Toolbar").ToolbarPane().Top()

Please be careful about the ownership - the following code may crash at any time when Go's GC starts to run:

dlg := wx.NewDialog(...)
bSizer := wx.NewBoxSizerT(wx.VERTICAL)    // Note the trailing T
dlg.SetSizer(bSizer)                      // dlg will own bSizer

If bSizer is collected by Go's GC, the wxBoxSizer object will also be freed. This may cause double-free error or other segmentation faults.

wx.NewCLASST is only a simple wrapper of wx.NewCLASS. For example:

func NewSizeT(a ...interface{}) Size {
    ret := NewSize(a...)
    ret.SwigTrackObject()
    return ret
}

As you can see, the trick is done by SwigTrackObject method. You can manually call it when you want Go's GC to delete the object, or call SwigUntrackObject method to let Go's GC not track it.

Conclusion

  • p := wx.NewCLASS / p.SwigUntrackObject(), p is owned by you (which means you are responsible for freeing it)
  • obj.TAKEOWN(p), p is owned by obj, and obj is responsible for freeing p. There are several methods that take the ownership of other objects, please refer the wxWidgets document.
  • p := wx.NewCLASST / p.SwigTrackObject(), p is owned by Go's GC (which means it will free the object when p is unreachable)

There are some special notes on wxFrame and wxDialog:

  • √ When we click the close botton of a wxFrame, by default the Destroy will be called and it will be deleted by itself (and also all children).
  • × However when we close a wxDialog, the Destroy won't be called by default and we have to manually destroy it.

Useful materials: