Q:

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 <class TBigObject>
class Container : public std::vector< std::shared_ptr<TBigObject> >
{
public:
    Container(int nToAllocate){ /* fill with default constructed TBigObjects */}
    Container(const Container& other){ /* deep copy */ }
    Container(Container&&) = default;
    Container& operator = (const Container& population){ /* deep copy */ }
    Container& operator = (Container&&) = 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 <class T>
using Container = std::vector< std::shared_ptr<T> >;

template <class T>
Container<T> defaultAllocate(int nItems);

template <class T>
Container<T> deepCopy(const Container<T>& other);

This looks more expressive, but using the code feels strange and verbose:
class Big;
Container<Big> someContainer = defaultAllocate(12);
Container<Big> copy = deepCopy(someContainer);

instead of:
class Big;
Container<Big> someContainer(12);
Container<Big> 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.

A:

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<typename T>
class Deep
{
   T*     value;
   public:
       Deep():                      value(NULL)         {}
       // Take ownership in this case.
       Deep(T const* value):        value(value)        {}
       Deep(T const& value):        value(new T(value)) {}
       ~Deep()                      {delete value;}
       Deep(Deep&& move)            {std::swap(value, move.value);}
       Deep(Deep const& copy)       {T* tmp = new T(*(copy.value));swap(tmp,value);delete tmp;}
       // Note this does do a deep copy via copy and swap
       Deep& operator=(Deep copy)   {std::swap(value, copy.value);return *this;}
       Deep& operator=(Deep&& 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&()                {return *value;}
       operator T const&() const    {return *value;}

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

