Question

In the actual C++ standard, creating collections satisfying following rules is hard if not impossible:

  1. exception safety,
  2. cheap internal operations (in actual STL containers: the operations are copies),
  3. automatic memory management.

To satisfy (1), a collection can't store raw pointers. To satisfy (2), a collection must store raw pointers. To satisfy (3), a collection must store objects by value.

Conclusion: the three items conflict with each other.

Item (2) will not be satisfied when shared_ptrs are used because when a collection will need to move an element, it will need to make two calls: to a constructor and to a destructor. No massive, memcpy()-like copy/move operations are possible.

Am I correct that the described problem will be solved by unique_ptr and std::move()? Collections utilizing the tools will be able to satisfy all 3 conditions:

  1. When a collection will be deleted as a side effect of an exception, it will call unique_ptr's destructors. No memory leak.
    • unique_ptr does not need any extra space for reference counter; therefore its body should be exact the same size, as wrapped pointer,
    • I am not sure, but it looks like this allows to move groups of unique_ptrs by using memmove() like operations (?),
    • even if it's not possible, the std::move() operator will allow to move each unique_ptr object without making the constructor/destructor pair calls.
  2. unique_ptr will have exclusive ownership of given memory. No accidental memory leaks will be possible.

Is this true? What are other advantages of using unique_ptr?

Was it helpful?

Solution

I agree entirely. There's at last a natural way of handling heap allocated objects.

In answer to:

I am not sure, but it looks like this allows to move groups of unique_ptrs by using memmove() like operations,

there was a proposal to allow this, but it hasn't made it into the C++11 Standard.

OTHER TIPS

Yes, you are right. I would only add this is possible thanks to r-value references.

When a collection will be deleted as a side effect of an exception, it will call unique_ptr's destructors. No memory leak.

Yes, a container of unique_ptr will satisfy this.

unique_ptr does not need any extra space for reference counter; therefore its body should be exact the same size, as wrapped pointer

unique_ptr's size is implementation-defined. While all reasonable implementations of unique_ptr using it's default destructor will likely only be a pointer in size, there is no guarantee of this in the standard.

I am not sure, but it looks like this allows to move groups of unique_ptrs by using memmove() like operations (?),

Absolutely not. unique_ptr is not a trivial class; therefore, it cannot be memmoved around. Even if it were, you can't just memmove them, because the destructors for the originals need to be called. It would have to be a memmove followed by a memset.

even if it's not possible, the std::move() operator will allow to move each unique_ptr object without making the constructor/destructor pair calls.

Also incorrect. Movement does not make constructors and destructors not be called. The unique_ptr's that are being destroyed need to be destroyed; that requires a call to their destructors. Similarly, the new unique_ptrs need to have their constructors called; that's how an object's lifetime begins.

There's no avoiding that; it's how C++ works.

However, that's not what you should be worried about. Honestly, if you're concerned about a simple constructor/destructor call, you're either in code that you should be hand-optimizing (and thus writing your own code for), or you're prematurely optimizing your code. What matters is not whether constructors/destructors are called; what matters is how fast the resulting code is.

unique_ptr will have exclusive ownership of given memory. No accidental memory leaks will be possible.

Yes, it will.

Personally, I'd say you're doing one of the following:

  • Being excessively paranoid about copying objects. This is evidence by the fact that you consider putting a shared_ptr in a container is too costly of a copy. This is an all-too-common malady among C++ programmers. That's not to say that copying is always good or something, but obsessing over copying a shared_ptr in a container is ridiculous outside of exceptional circumstances.

  • Not aware of how to properly use move semantics. If your objects are expensive to copy but cheap to move... then move them into the container. There's no reason to have a pointer indirection when your objects already contain pointer indirections. Just use movement with the objects themselves, not unique_ptrs to objects.

  • Disregarding the alternatives. Namely, Boost's pointer containers. They seem to have everything you want. They own pointers to their objects, but externally they have value semantics rather than pointer semantics. They're exception safe, and any copying happens with pointers. No unique_ptr constructor/destructor "overhead".

It looks like the three conditions I've enumerated in my post are possible to obtain by using Boost Pointer Container Library.

This question illlustrates why I so love the Boehm garbage collector (libgc). There's never a need to copy anything for reasons of memory management, and indeed, ownership of memory no longer needs to be mentioned as part of APIs. You have to buy a little more RAM to get the same CPU performance, but you save hundreds of hours of programmers' time. You decide.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top