Question

I like std::unique_ptr. It helps me out to prevent memory leaks, which is extremely useful. But there's one problem: copy assignment and construction is not allowed.

Even though this restriction serves safety of a programmer, it is quite limiting, too. If you work with classes with std::unique_ptr as their member(s) using copy assignment and construction, you end up having problems. That's why I created my own wrapper around unique_ptr with copy construction and assignment. Here's it's copy constructor:

template<typename T, class Deleter>
PointerSmartSafe<T, Deleter>::PointerSmartSafe(PointerSmartSafe const& pointer_smart_safe_) noexcept : _m_opPointerUnique((_m_opPointerUnique == nullptr) ? new T(*_m_opPointerUnique.get()) : nullptr){

}

And here's the copy assignment operator:

template<typename T, class Deleter>
PointerSmartSafe<T, Deleter>& PointerSmartSafe<T, Deleter>::operator=(PointerSmartSafe const& pointer_smart_safe_) noexcept{
    _m_opPointerUnique = decltype(_m_opPointerUnique)(new T(*_m_opPointerUnique.get()));
    return *this;
}

Everything worked fine until I ended up using abstract base class as a type (T). I got an error message like the following:

error: cannot allocate an object of abstract type 'AbstractBaseClass'

This perplexes me. Does there exist a workaround?

Was it helpful?

Solution

But there's one problem: copy assignment and construction is not allowed.

That is not a problem. If you find it a problem you're doing something wrong.

Even though this restriction serves safety of a programmer, it is quite limiting, too.

It's limiting intentionally, maybe you should reconsider your design.

That's why I created my own wrapper around unique_ptr with copy construction and assignment.

What you want is not a unique_ptr then, you want a "clone ptr"

This perplexes me

What's perplexing about it? You're trying to create an instance of an abstract base class. Your code would also slice non-abstract bases. It's inherently unsafe.

This should tell you something important: Copying the object held by a unique_ptr cannot be done generically, it requires context that the unique_ptr doesn't have. That context either has to come from the object that owns the thing you want to copy (which requires the owning object to know the object's dynamic type) or from the thing you want to copy itself (which can use virtual functions to make a copy in the context of the correct dynamic type.)

A conventional solution is to add a virtual clone() member function to your types and then use that when possible.

You could incorporate that into your constructor something like this:

template<typename T>
  auto clone(T* t) -> decltype(t->clone())
  { return t->clone(); }

template<typename T>
  std::unique_ptr<T> clone(T* t, ...)
  { return std::unique_ptr<T>(new T(*t)); }

// ... 

_m_opPointerUnique((_m_opPointerUnique == nullptr) ? clone(_m_opPointerUnique.get()) : nullptr)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top