How to design interface of deep-copy behaving pointer containers? I want to make a container which manages big objects. which performs deep copies on copy construction and copy assignment. I also like the interface of the std containers, so I wanted to implement it using public inheritance:

template &lt;class TBigObject&gt;
class Container : public std::vector&lt; std::shared_ptr&lt;TBigObject&gt; &gt;
{
public:
    Container(int nToAllocate){ /* fill with default constructed TBigObjects */}
    Container(const Container&amp; other){ /* deep copy */ }
    Container(Container&amp;&amp;) = default;
    Container&amp; operator = (const Container&amp; population){ /* deep copy */ }
    Container&amp; operator = (Container&amp;&amp;) = default;
};


I heard of the "Thou shalt not inherit from std containers" maxim and the reasons behind it. So I decided to make an alternative:

template &lt;class T&gt;
using Container = std::vector&lt; std::shared_ptr&lt;T&gt; &gt;;

template &lt;class T&gt;
Container&lt;T&gt; defaultAllocate(int nItems);

template &lt;class T&gt;
Container&lt;T&gt; deepCopy(const Container&lt;T&gt;&amp; other);


This looks more expressive, but using the code feels strange and verbose:

class Big;
Container&lt;Big&gt; someContainer = defaultAllocate(12);
Container&lt;Big&gt; copy = deepCopy(someContainer);


instead of:

class Big;
Container&lt;Big&gt; someContainer(12);
Container&lt;Big&gt; copy = someContainer;


I am a beginner programmer and I don't want to make errors early on. I would like to ask your advice on which choice to make. Or even better, if there is a third option.
I think you are going about it the wrong way.

Containers already perform copy on copy construction/assignment because they are designed for value objects not pointers. What you really want is a wrapper object for pointers that performs a deep copy when that object is copied.

This has the added advantage of working with all containers.

If you define the move operators then it also works well with re-size operations as the move semantics will be applied to the wrapper when the the container is re-sized.

The other advantage here is you can make the wrapper behave like the underlying type. So you get easy access to all the algorithms.

template&lt;typename T&gt;
class Deep
{
   T*     value;
   public:
       Deep():                      value(NULL)         {}
       // Take ownership in this case.
       Deep(T const* value):        value(value)        {}
       Deep(T const&amp; value):        value(new T(value)) {}
       ~Deep()                      {delete value;}
       Deep(Deep&amp;&amp; move)            {std::swap(value, move.value);}
       Deep(Deep const&amp; copy)       {T* tmp = new T(*(copy.value));swap(tmp,value);delete tmp;}
       // Note this does do a deep copy via copy and swap
       Deep&amp; operator=(Deep copy)   {std::swap(value, copy.value);return *this;}
       Deep&amp; operator=(Deep&amp;&amp; move) {std::swap(value, move.value);return *this;}

       // Note: undefined behavior if used when value is NULL.
       //       You may want to add logic here depending on use case.
       operator T&amp;()                {return *value;}
       operator T const&amp;() const    {return *value;}

       T* release()                 {T* tmp = value;value = NULL;return tmp;}
};
int main()
{
    std::vector&lt;Deep&lt;int&gt;&gt;   deep(5,7);
}