n2liquid's sandbox

Herb Sutter’s GotW #105 – Smart Pointers, Part 3: Solution attempt

Posted on: February 17, 2013

So, I’ve been waiting for the solution to this GotW for many months. Finally I’m giving up on it and just providing my one, for fun. The solution was longer than I expected.

I’m not sure if this is correct, but this is how I see things. Solution to Guru Question:

– widget & – No ownership acquisition – shared or not – is to be allowed. The function is granted the priviledge of modifying the widget. If no change is ever needed by the function, the reference should be to const widget.

– widget * – Same as widget &, but nullable. Same const recommendations apply to the pointed widget. Making the pointer const doesn’t affect the API semantics in any way, but only the internal (as in “inside the function body”) semantics of the pointer.

– unique_ptr<widget> – Causes transfer of unique ownership. This should be used if the widget is not to be usable by the calling function anymore.

This must not be used if pointers or references are kept to the widget anywhere else outside of the function being called, including the calling site / calling function, unless there are documented API guarantees about the transferred widgets’ lifetime. Since those guarantees are not enforced by the compiler, their reliability (and therefore “dangerousness”) rests upon the API developers’ diligence in keeping the program behavior up to the API documented specifications.

Using const widget would be a bit strange, but OK. It would mean the widget is “frozen” and would not be allowed to change forevermore (until it’s deleted).

Using const unique_ptr would be even weirder, but OK again. It would guarantee that the widget is going to be destroyed just before the function exits, but could nevertheless be used, manipulated, and copied at will during the course of its execution. Keeping another reference to it and using it later in this case is a surefire memory corruption caused by usage of deleted object.

Using const widget would additionally cause the freezing behavior described above.

– unique_ptr<widget> & – Represents a potential transfer of unique ownership. Whether it’s going to happen or not is deferred to the called function body (as opposed to being enforced at the call site), possibly causing it to depend on runtime factors (e.g. if it happens inside an if statement).

The call site might want to check whether its unique handle has been nullified or not after the call.

– shared_ptr<widget> – Represents either copy or transfer of shared ownership.

Copy of shared ownership happens when the argument expression is an lvalue, which implies copy construction of the shared_ptr, and therefore a (thread-safe) refcount increment.

Transfer of shared ownership happens when the argument expression is an rvalue, which implies move construction of the shared_ptr, and therefore no refcount increment. Since no refcount needs to be incremented, no synchronization effort happens in this operation.

Copy should be used when the original ownership is to be kept.

Transfer should be used when the original ownership is not needed anymore (i.e. the calling function does not need to use the widget anymore). This doesn’t mean the widget can’t have shared ownership elsewhere in the program beyond the callee, it’s just that the shared handle at the calling function is transferred to the called function. This is pretty much just an “optimization best-practice” sort of thing to avoid the thread synchronization efforts that happen during copy.

const widget should be used in both cases if the widget is not to be modified by the function being called.

Using const shared_ptr has no bearing on the semantics of the API. It would only affect the usage of the shared_ptr in the function being called (the pointer would not be reassignable, just like naked const pointers wouldn’t).

– shared_ptr<widget> & – Represents a potential copy or transfer of shared ownership. Whether they are going to happen – and also the choice of *which* is going to happen! – is deferred to the called function body, and those may only be determinable during runtime (e.g. if the copy or move happen inside if statements).

In this case, one might want to check whether the shared_ptr wasn’t nullified by a transfer inside the called function before dereferencing it.

const widget also should be used if the widget is not to be modified by the function being called.

Using const shared_ptr & also has no bearing on the semantics of the API. It allows for an interesting optimization described here by Nicolas (I love those guys from Lounge<C++>), however, at the very end of that comment: if the immediately called function doesn’t need shared ownership over the object for itself, but another function it calls does, passing a const shared_ptr & first allows the function to bypass useless refcount updates, cheaply forwarding the shared ownership to functions that actually need it (in other words, taking a shared_ptr). This is possible because you can create shared_ptrs from const shared_ptrs.

A reference to a shared_ptr can also be used when the function is supposed to make changes or otherwise deal with the pointer itself, as pointed out in this StackOverflow answer.

Realistically speaking, I believe it’s highly unlikely there is any practical usage for passing unique_ptr or shared_ptr by reference for potential copies or transfers. If you encounter such a need, you should probably hold on for a second and rethink, since it’s a code smell. There is probably a better way to do it. But if not, well, it works, so go ahead. Just know that people can be confused by these kinds of smart pointer usage, and at the very least use assertions to make sure the pointers aren’t null after the potential moves. And, of course, know what you’re doing.

If you have any questions, ask them in the comments section! Also, if I made I mistake (quite likely since I haven’t really tested any of these assertives), please let me know, too! Kuppo!

Final Fantasy XIII-2 Moggle Artwork

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Cute bouncing pixels

un.ma.i!

Twitter (technical)

Error: Twitter did not respond. Please wait a few minutes and refresh this page.

Twitter (personal)

Error: Twitter did not respond. Please wait a few minutes and refresh this page.

Get messaged when I post something new!
Just enter your e-mail and hit Follow:

Join 171 other followers

%d bloggers like this: