weak_ptr smart shared_ptr pointer example create c++ smart-pointers c++11

shared_ptr - smart pointers c++



C++ 0x unique_ptr reemplaza a scoped_ptr tomando posesión? (5)

Solía ​​escribir código como este:

class P {}; class Q: public P {}; class A { // takes ownership A(P* p): p_(p) {} scoped_ptr<P> p_; }; A a(new Q);

Con C ++ 0x, debo reescribir la clase A como:

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


Edit: mi mal, usted necesita escribir el move(p) dentro del inicializador. std::move trata lo que sea como una referencia de valor, y en su caso, aunque su argumento sea una referencia de valor a algo, pasarlo a otra cosa (como el constructor de p_ ) pasará una referencia de valor lval, nunca un valor de r referencia por defecto.

Por el comentario de Karu, también se agregaron los complementos necesarios para compilar mi código.

Por ejemplo:

#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; }

Además, en su ejemplo original, debería reescribir la clase A de la siguiente manera:

clase A {// toma posesión A (unique_ptr

&& p): p_ (std :: move (p)) {}

unique_ptr<P> p_;

};


En mi opinión, es mejor usar unique_ptr ya que proporciona una característica adicional: mover la semántica . es decir, puede escribir un constructor de movimiento, etc. para su clase, a diferencia de scoped_ptr . Además, unique_ptr no tiene una sobrecarga asociada, como es el caso de scoped_ptr , por lo que es una instalación superior. Una decisión de reescritura depende de usted, por supuesto, en caso de que no necesite mover la semántica, entonces no hay ningún punto de la reescritura. No olvide que unique_ptr es de la biblioteca estándar, por lo que debe proporcionarse con cualquier implementación compatible de C ++ 0x (cuando se convierta en realidad, por supuesto :)


He subestimado la respuesta de Comonad, pero con una advertencia:

Siempre que desee rechazar explícitamente la semántica de movimiento, utilice un scoped_ptr const unique_ptr .

No he encontrado ningún caso de uso en el que const std::unique_ptr sea ​​inferior a boost::scoped_ptr . Sin embargo estoy abierto a la educación sobre el tema.

Editar:

Aquí hay un caso de uso de boost::scoped_ptr que creo que debería fallar, pero no lo hace. std::unique_ptr para 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''; }

Si la promesa de boost::scoped_ptr es que su recurso no escapará al alcance actual, entonces no es tan bueno para mantener esa promesa como una const std::unique_ptr . Si queremos comparar const boost :: scoped_ptr con const :: std :: unique_ptr, tengo que preguntar: ¿para qué? Me parecen lo mismo, excepto que a const std :: unique_ptr permite la construcción y destrucción personalizadas.


Tengo que estar en desacuerdo con AraK porque uno es superior. No existe una opción superior entre los dos, ya que a menudo depende del uso. Es como decir que un SmartCar es superior a una camioneta pick-up para todos los usos porque es más ligero y más rápido. En realidad, a veces necesitas un camión y otras veces no. Su elección de puntero debe basarse en lo que necesita.

Lo bueno de scoped_ptr es que agrega un nivel de seguridad. Al usar scoped_ptr, usted está consciente de que la memoria creada existirá solo para ese ámbito y no más, por lo que obtiene protección en tiempo de compilación contra los intentos de moverla o transferirla.

Por lo tanto, si desea crear algo pero limitar su alcance, utilice scoped_ptr. Si desea crear algo y que la propiedad sea móvil, use unique_ptr. Si desea crear algo y compartir ese puntero y la limpieza cuando todos los referentes hayan desaparecido, use shared_ptr.


  • Un auto_ptr es un puntero con copia y con semántica de movimiento y propiedad (= auto-delete).
  • Un unique_ptr es un auto_ptr sin copia pero con movimiento semántico.
  • Un scoped_ptr es un auto_ptr sin copia y sin movimiento de semántica.

    auto_ptr ‍s siempre es una mala elección , eso es obvio.

    Siempre que desee mover explícitamente la semántica, use un unique_ptr .

    Siempre que desee deshabilitar explícitamente la semántica de movimiento, use scoped_ptr .

  • Todos los punteros permiten la semántica de intercambio , como p.swap(q) . Para no permitirlos, use cualquier const ... _ptr .

Hay situaciones en las que desea utilizar un scoped_ptr que apunta a uno de varios objetos intercambiables: debido a la ausencia de semántica de movimientos, es bastante seguro (con respecto a errores obvios) que no apuntará accidentalmente a nulo debido a una no intencional movimiento. Vale la pena mencionar: scoped_ptr ‍s todavía se puede intercambiar de manera eficiente. Para que sea móvil y / o copiable, pero aún con estas semánticas de intercambio, es posible que desee considerar el uso de shared_ptr que apunta a scoped_ptr que apunta a un objeto intercambiable (a través de scoped_ptr :: swap).

Vea :smart-pointers-boost-explained para más detalles.