VclPtr a refresher ...

Michael Meeks michael.meeks at collabora.com
Thu May 18 17:37:31 UTC 2017


Hi guys,

	We've been fixing a few resource leaks recently, and I suspect it would
pay to remind people of the documentation on VclPtr:

https://gerrit.libreoffice.org/gitweb?p=core.git;a=blob;f=vcl/README.lifecycle;h=6ef91ccfce51d4b5daeb7d03527f471233ae71ab;hb=HEAD

	I guess I should update that now the transitional stuff is obsolete.
But here is the punch-line:

	**** please call disposeAndClear() ****
or, use:
	ScopedVclPtrInstance<Foo> aFoo(...);

	which will do it for you when your variable goes out of scope.

* Wait but why ?

	VclPtr is very much like a shared_ptr<> or any other such
smart-reference counting thing (it differs for only rather boring
reasons). What is different is VCL; so take for example this:

{
	VclPtr<VirtualDevice> xDev(VirtualDevice::Create());
	// VclPtrInstance<VirtualDevice> xDev; - its synonym.

	... do something temporary with xDev ...
} // exit scope.

	It looks safe, what could go wrong ? the smart pointer will go out of
scope, and xDev will be deleted - right ? it is not easy to see anyone
else taking a reference to xDev ... so ...

	Beware - the reason is that VCL is infested with scads of lists of
internal smart pointers all to each other:

include/vcl/virdev.hxx
class VCL_DLLPUBLIC VirtualDevice : public OutputDevice {
  private:
    VclPtr<VirtualDevice>  mpPrev;
    VclPtr<VirtualDevice>  mpNext;

	Oh dear - each VirtualDevice is part of a manually maintained linked
list of safe but problematic VirtualDevices. And to add insult to injury
we have:

include/vcl/outdev.hxx
class VCL_DLLPUBLIC OutputDevice : public virtual VclReferenceBase {
  private:
    mutable VclPtr<OutputDevice>    mpPrevGraphics; ...
    mutable VclPtr<OutputDevice>    mpNextGraphics; ...

	So - each VirtualDevice is part of two doubly linked lists. Windows
(derived from OutputDevice) takes part in many more hierarchical
structures too ...

* Summary:

	Calling dispose is a good plan ! =) This releases all of these
references, lists etc. and also frees any underlying resources - leaving
only an empty shell of an object around until the last object is released.

	So:
{ // correct
	VclPtrInstance<VirtualDevice> xDev;
	... do something temporary with xDev ...
	xDev.disposeAndClear()
}

	Or better:
{ // correct
	ScopedVclPtrInstance<VirtualDevice> xDev;
	...
} // auto-disposes outside the scope.


* Why bother with a smart pointer then ?

	So - since we have to replace what would be a 'delete' with a
disposeAndClear() anyway - why bother in the first instance ? the answer
here is that LibreOffice is quite good at getting deep call stacks
around even emission, referencing Windows and being sure that the Window
is still alive, and has a valid handle (so we can reliably check it is
alive) as we return through those makes life lots cleaner and easier.
The nice thing about vclptr is that you can call disposeAndClear several
times from different paths in different orders, and you can be sure that
if the pointer is not NULL it is always valid.

	I hope that helps someone - very happy to help if anyone is in doubt etc.

	ATB,

		Michael.

-- 
michael.meeks at collabora.com <><, Pseudo Engineer, itinerant idiot


More information about the LibreOffice mailing list