For me "non-owning pointers" are nearly non-existant. If I will be storing a pointer to an object in a member variable, then there is some kind of ownership in play, even if it is weak ownership. If this is for passing arguments to a method, then there are references (which have none of the problems you mention).
The only exception I can think of is when iterating through a raw array, maybe serializing/deserializing binary data. In that case I want to be able to do pointer math, but not deletion. But it would be incredibly difficult to accidently delete a pointer, especially when I hardly use delete anyways!
Gtk::manage()
solves the specific problem of lifetime management for hierarchies of widgets. And it solves it well.
Smart pointers (std::shared_ptr
in particular) have broader application range, and therefore will be less efficient when used to address this specific problem. Lifetime management for hierarchies of widgets can be solved with shared_ptr
, but it will be:
- not as concise as using
manage()
(as you pointed out yourself);
- less efficient in terms of memory usage, since using
shared_ptr
s will introduce memory overhead: shared_ptr
has a memory footprint of its reference to its reference-count, which will use size - as opposed to manage()
, which uses variables such as Gtk::Object.referenced_
that are part of your Widget
base class already at all times. So, if you have a significant number of Widgets
, that size difference might become an issue worth considering;
- not as mainstream as using
manage()
in gtkmm (which has quite a few consequences, including clarity and maintainability).
As of idea of favoring std::shared_ptr
over Gtk::manage()
because shared_ptr
is part of C++ Standard, while manage()
is not - I'm not sure it is going to be a game changer for average application, as by not using manage()
you don't cut your dependency on Gtk anyways. So your application is not going to gain any better portability if you'd go for shared_ptr
.
I would rather leverage native gtkmm API, for sake of clarity and efficiency.
P.S.: There is actually a smart pointer Glib::RefPtr
, which handles lifetime management for certain gtkmm objects. Again, as it is a feature native to Glib, it leverages built-in facilities of Glib::ObjectBase
, and is therefore more efficient then std::shared_ptr
for certain applications, for the reasons explained in the 2nd point above.
Best Answer
No, it's not enough to deal with the raw pointer in the destructor. You also have to deal with it in the copy constructor and assignment operator functions. It's usually not enough to simply copy the pointer (which the compiler will happily do for you); you probably really want to make a copy of the resource it points to. And you have to remember to gracefully handle self-assignment without leaking the resource. Maybe you don't want to support copying at all, so you have to remember to explicitly disable those functions. Maybe you want to give out handles to that resource, so you have to keep track of when it's safe to be freed. What if an exception is thrown in the middle of your constructor? What if you aren't the one throwing it? Maybe there's another edge case I haven't thought of.
(Note: I've debugged more than enough of this kind of code that gets it wrong, hence my somewhat harsh tone.)
If you want to get it right on the first try, then yes, you should go with a smart pointer type such as
boost::scoped_ptr
orstd::tr1::shared_ptr
.