Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++0x unique_ptr replaces scoped_ptr taking ownership?

I used to write code like this:

class P {};

class Q: public P {};

class A {
    // takes ownership
    A(P* p): p_(p) {}

    scoped_ptr<P> p_;
};

A a(new Q);

With C++0x, should I rewrite class A as:

class A {
    // takes ownership
    A(unique_ptr<P>&& p): p_(p) {}

    unique_ptr<P> p_;
};
like image 563
Neil G Avatar asked Jun 11 '10 00:06

Neil G


4 Answers

  • A auto_ptr is a pointer with copy and with move semantics and ownership (=auto-delete).
  • A unique_ptr is a auto_ptr without copy but with move semantics.
  • A scoped_ptr is a auto_ptr without copy and without move semantics.

    auto_ptr‍s are allways a bad choice – that is obvious.

    Whenever you want to explicitely have move semantics, use a unique_ptr.

    Whenever you want to explicitely disallow move semantics, use a scoped_ptr.

  • All pointers allow swap semantics, like p.swap(q). To disallow those, use any const …_ptr.

There are situations, where you want to use a scoped_ptr pointing to one of several interchangeable objects: Because of the absence of move semantics, it is quite safe (in respect to obvious bugs) that it will not accidentally point to null because of an unintended move. Worth to mention: scoped_ptr‍s can still be swap‍ped efficiently. To make it movable and/or copyable – but still with these swap semantics – you might want to consider using a shared_ptr pointing to a scoped_ptr pointing to an exchangeable (via scoped_ptr::swap) object.

See stackoverflow:smart-pointers-boost-explained for further details.

like image 36
comonad Avatar answered Nov 02 '22 22:11

comonad


I've upvoted comonad's answer, but with a caveat:

Whenever you want to explicitely disallow move semantics, use a scoped_ptr const unique_ptr.

I have not come across any use cases where a const std::unique_ptr is inferior to a boost::scoped_ptr. However I'm open to education on the subject.

Edit:

Here is a use case of boost::scoped_ptr that I think should fail, but does not. It does fail for std::unique_ptr:

#include <iostream>

#ifdef USE_UNIQUEPTR

#include <memory>
typedef std::unique_ptr<int> P;

#else  // USE_UNIQUEPTR

#include <boost/scoped_ptr.hpp>
typedef boost::scoped_ptr<int> P;

#endif  // USE_UNIQUEPTR

int main()
{
    P p1(new int(1));
    {
        // new scope
#ifdef USE_UNIQUEPTR
        const P p2(new int(2));
#else  // USE_UNIQUEPTR
        P p2(new int(2));
#endif  // USE_UNIQUEPTR
        swap(p1, p2);  // should fail!
    }
    std::cout << *p1 << '\n';
}

If the promise of boost::scoped_ptr is that its resource will not escape the current scope, then it is not as good at holding that promise as a const std::unique_ptr. If we want to compare const boost::scoped_ptr to const::std::unique_ptr, I have to ask: for what purpose? They seem the same to me, except that a const std::unique_ptr allows customized construction and destruction.

like image 110
Howard Hinnant Avatar answered Nov 03 '22 00:11

Howard Hinnant


IMO it is better to use unique_ptr as it provides an additional feature: move semantics. i.e. you can write a move constructor, etc for your class, unlike scoped_ptr. Also, unique_ptr doesn't have an overhead associated with it as it is the case with scoped_ptr, so it is a superior facility. A decision of a rewrite is up to you of course, in case you don't need move semantics then there is no point of the rewrite. Don't forget that unique_ptr is from the standard library, so it must be provided with any compliant implementation of C++0x(when it becomes reality of course :)!

like image 2
Khaled Alshaya Avatar answered Nov 03 '22 00:11

Khaled Alshaya


I have to disagree with AraK on one being superior. There is no such thing as a superior choice between the two as it often depends on usage. That's like saying a SmartCar is superior to a pick-up truck for all uses because it's lighter and faster. In reality, sometimes you need a truck and sometimes you don't. Your choice of pointer should be based on what you need.

The nice thing about scoped_ptr is it adds a level of safety. By using scoped_ptr you are delcaring that the memory created will exist only for that scope and no more, thus you get compile-time protection against attempting to move it or transfer it.

So, if you want to create somethign but limit it's scope, used scoped_ptr. If you want to create something and have ownership be movable, use unique_ptr. If you want to create something and share that pointer and cleanup when all referencers are gone, use shared_ptr.

like image 2
James Michael Hare Avatar answered Nov 02 '22 23:11

James Michael Hare