1

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?

ildjarn
  • 62,044
  • 9
  • 127
  • 211
Helixirr
  • 911
  • 9
  • 18

1 Answers1

7

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)
Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
  • Thank you for your answer. It looks very promising solution. I'll try to take advantage of this. Your name will be put into my source code (for helping me out), if you don't mind. :) – Helixirr Mar 27 '13 at 13:18
  • 2
    @Helixirr I wrote one of these called a `value_ptr` (it emulates value semantics on a pointer). You'll want to implement both move and copy. Mine detected the existence of `T()->Clone() const` and `T()->clone() const` methods, as well as free `Clone(T const*)` and `clone(T const*)` functions, with a default `clone(T const*)` that was only valid for `T` that could be copy constructed (via traits) and did `new T(*t)`. Oh, and don't forget to support `value_ptr = value_ptr` when `U` is a subclass of `T`, or maybe even copy-constructable? – Yakk - Adam Nevraumont Mar 27 '13 at 19:31
  • @Yakk: I have copy assignment operator and construction already. Thanks for helping. – Helixirr Mar 27 '13 at 20:09
  • 1
    @Helixirr I hope you mean `move` -- you want both `move` and `copy`. :) – Yakk - Adam Nevraumont Mar 27 '13 at 20:10