Search code examples
c++c++14unique-ptr

unique_ptr that contains unique_ptr


Disclaimer: I at first wrote a version of the question that I thought would be clear but that wasn't at all. I've reworked it here as a MRE.

I have the following bit of code:

#include <map>
#include <memory>
#include <string>

using std::make_unique;
using std::string;
using std::unique_ptr;

template <typename T>
class Holder {
   public:
    Holder() {}
    ~Holder() {}
   private:
    T value_;  // In real life, we can do something with this.
};

struct Thing {
    Thing() {}
};
class ThingCollection {
   public:
    ThingCollection() {}

   private:
    // In real life, I have more maps of <string, Thing*>.
    // Which is why I use a unique_ptr in the map.
    std::map<string, unique_ptr<Thing>> the_map_;
};

My issue is making a unique_ptr to a Holder<ThingCollection>, which fails due to a missing copy constructor.

void foo() {
    Holder<ThingCollection> cm;  // OK.
    auto cmp1 = make_unique<Holder<int>>(Holder<int>());  // OK.
    auto cmp2 = make_unique<ThingCollection>(ThingCollection());    // OK.
    auto cmp3 = make_unique<Holder<int>>(Holder<int>()); // OK.
    auto cmp4 = make_unique<Holder<ThingCollection>>(Holder<ThingCollection>()); // BAD.

}

On compiling, the final (BAD) line fails due to a copy constructor (of unique_ptr) being implicitly deleted. I understand why unique_ptr is not copyable, but I don't understand why it wants to copy here or what the right response is.

I compiled thus:

clang++ -std=c++14 -pthread -Wall -Wextra -c -o mre.o mre.cc

Solution

  • This, of course, leads to errors about implicitly-deleted copy constructors. I think I understand why this is so

    You generally get such errors when you try to copy objects of a type that has non-copyable members.

    Solution: Don't try to copy non-copyable objects.


    Disclaimer: Obviously a unique_ptr can't manage something that itself contains a unique_ptr, at least not in any naive way.

    On the contrary, unique pointer can easily manage something that itself contains a unique pointer. The only case I can think of where naive approach would fail is when pointers form a recursive chain - essentially a linked list - in which case you need a custom destructor to avoid linear recursion depth.

    P.S. Instead of your ThingCollection class, I recommend using boost::multi_index_container.