I’ve written a static factory method that returns a new Foobar object populated from another data object. I’ve recently been obsessed with ownership semantics and am wondering if I’m conveying the right message by having this factory method return a unique_ptr.
class Foobar {
public:
static unique_ptr<Foobar> factory(DataObject data);
}
My intent is to tell client code that they own the pointer. Without a smart pointer, I would simply return Foobar*. I would like, however, to enforce that this memory be deleted to avoid potential bugs, so unique_ptr seemed like an appropriate solution. If the client wants to extend the lifetime of the pointer, they just call .release() once they get the unique_ptr.
Foobar* myFoo = Foobar::factory(data).release();
My question comes in two parts:
- Does this approach convey the correct ownership semantics?
- Is this a “bad practice” to return
unique_ptrinstead of a raw pointer?
Returning a
std::unique_ptrfrom a factory method is just fine and should be a recommended practice. The message it conveys is (IMO): You are now the sole owner of this object. Furthermore, for your convenience, the object knows how to destroy itself.I think this is much better then returning a raw pointer (where the client has to remember how and if to dispose of this pointer).
However I do not understand your comment about releasing the pointer to extend it’s lifetime. In general I rarely see any reason to call
releaseon a smartpointer, since I think pointers should always be managed by some sort of RAII structure (just about the only situation where I callreleaseis to put the pointer in a different managing datastructure, e.g. aunique_ptrwith a different deleter, after I did something to warrant additional cleanup) .Therefore the client can (and should) simply store the
unique_ptrsomewhere (such as anotherunique_ptr, which has been move constructed from the returned one) as long as they need the object (or ashared_ptr, if they need multiple copies of the pointer). So the clientside code should look more like this:Personally I would also add a
typedeffor the returned pointer type (in this casestd::unique_ptr<Foobar>) and or the used deleter (in this case std::default_deleter) to your factory object. That makes it easier if you later decide to change the allocation of your pointer(and therefore need a different method for destruction of the pointer, which will be visible as a second template parameter ofstd::unique_ptr).So I would do something like this: