С++ 0x unique_ptr заменяет scoped_ptr на владение?
Я использовал для написания кода следующим образом:
class P {};
class Q: public P {};
class A {
// takes ownership
A(P* p): p_(p) {}
scoped_ptr<P> p_;
};
A a(new Q);
С С++ 0x следует переписать класс A как:
class A {
// takes ownership
A(unique_ptr<P>&& p): p_(p) {}
unique_ptr<P> p_;
};
Ответы
Ответ 1
Я вернул ответ comonad, но с оговоркой:
Всякий раз, когда вы хотите явно disallow переместить семантику, используйте scoped_ptr const unique_ptr.
Я не сталкивался с целями использования, когда const std::unique_ptr
уступает boost::scoped_ptr
. Однако я открыт для обучения по этому вопросу.
Edit:
Вот пример использования boost::scoped_ptr
, который, как мне кажется, должен потерпеть неудачу, но это не так. Он не работает для 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';
}
Если обещание boost::scoped_ptr
заключается в том, что его ресурс не исчезнет из текущей области, то это не так хорошо, если вы держите это обещание как const std::unique_ptr
. Если мы хотим сравнить const boost:: scoped_ptr с const:: std:: unique_ptr, я должен спросить: с какой целью? Они кажутся мне одинаковыми, за исключением того, что const std:: unique_ptr позволяет настраивать конструкцию и разрушение.
Ответ 2
- A auto_ptr - это указатель с копией и с перемещать семантику и право собственности (= автоматическое удаление).
- A unique_ptr - это auto_ptr без копирования, но с перемещать семантику.
-
A scoped_ptr - auto_ptr без копирования и без семантики перемещения.
auto_ptr - это всегда плохой выбор - это очевидно.
Если вы хотите явно иметь переместить семантику, используйте unique_ptr.
Всякий раз, когда вы хотите явно запретить перемещать семантику, используйте scoped_ptr.
-
Все указатели позволяют использовать swap семантику, например p.swap(q)
. Чтобы запретить их, используйте любой const... _ptr.
Есть ситуации, когда вы хотите использовать scoped_ptr, указывающий на один из нескольких взаимозаменяемых объектов: из-за отсутствия семантики перемещения это совершенно безопасно (в отношении очевидных ошибок), что это не будет случайно указывать на нуль из-за непреднамеренного перемещения. Стоит упомянуть: scoped_ptr s может быть эффективно swap. Чтобы сделать его подвижным и/или скопированным, но все же с помощью семантики swap, вы можете рассмотреть возможность использования shared_ptr, указывающего на scoped_ptr, указывающий на сменный (через scoped_ptr:: swap).
Подробнее см. fooobar.com/questions/6730/....
Ответ 3
IMO лучше использовать unique_ptr
, поскольку он предоставляет дополнительную функцию: перемещать семантику. т.е. вы можете написать конструктор перемещения и т.д. для вашего класса, в отличие от scoped_ptr
. Кроме того, unique_ptr
не имеет связанных с ним служебных данных, как в случае с scoped_ptr
, поэтому это превосходное средство. Решение переписывания зависит от вас, конечно, если вам не нужна семантика перемещения, тогда нет смысла переписывать. Не забывайте, что unique_ptr
из стандартной библиотеки, поэтому он должен быть снабжен любой совместимой реализацией С++ 0x (когда это становится реальностью, конечно:)!
Ответ 4
Я должен не согласиться с AraK на том, что кто-то выше. Нет такой вещи, как превосходный выбор между ними, поскольку это часто зависит от использования. Это, как сказать, SmartCar превосходит пикап для всех применений, потому что он легче и быстрее. В действительности, иногда вам нужен грузовик, а иногда нет. Ваш выбор указателя должен основываться на том, что вам нужно.
Хорошая вещь о scoped_ptr - это уровень безопасности. Используя scoped_ptr, вы делаете вывод, что созданная память будет существовать только для этой области и не более, поэтому вы получаете защиту от компиляции, пытаясь ее переместить или передать.
Итак, если вы хотите создать somethign, но ограничите его область, используйте scoped_ptr. Если вы хотите что-то создать и иметь право собственности, используйте unique_ptr. Если вы хотите что-то создать и поделиться этим указателем и очисткой, когда все реферисты исчезли, используйте shared_ptr.
Ответ 5
Изменить: мне плохо, вам нужно написать move(p)
внутри инициализатора. std::move
обрабатывает все, что задано в качестве ссылки rvalue, и в вашем случае, хотя ваш аргумент является ссылкой rvalue на что-то, передача его в нечто другое (например, конструктор p_
) будет передавать ссылку lvalue, а не ссылку rvalue по умолчанию.
В комментарии к Karu также добавлено необходимое количество, чтобы скомпилировать мой код.
Например:
#include <memory>
#include <cassert>
#include <vector>
using namespace std;
class A {};
class B {
public:
void takeOwnershipOf(unique_ptr<A>&& rhs) {
// We need to explicitly cast rhs to an rvalue when passing it to push_back
// (otherwise it would be passed as an lvalue by default, no matter what
// qualifier it has in the argument list). When we do that, the move
// constructor of unique_ptr will take ownership of the pointed-to value
// inside rhs, thus making rhs point to nothing.
owned_objects.push_back(std::move(rhs));
}
private:
vector<unique_ptr<A>> owned_objects;
};
int main() {
unique_ptr<B> b(new B());
// we don't need to use std::move here, because the argument is an rvalue,
// so it will automatically be transformed into an rvalue reference.
b->takeOwnershipOf( unique_ptr<A>(new A()) );
unique_ptr<A> a (new A());
// a points to something
assert(a);
// however, here a is an lvalue (it can be assigned to). Thus we must use
// std::move to convert a into an rvalue reference.
b->takeOwnershipOf( std::move(a) );
// whatever a pointed to has now been moved; a doesn't own it anymore, so
// a points to 0.
assert(!a);
return 0;
}
Кроме того, в вашем исходном примере вам следует переписать класс A следующим образом:
класс A { // получает право собственности A (unique_ptr
& p): p_ (std:: move (p)) {}
unique_ptr<P> p_;
};