2008-09-26 16 views
76

Estoy haciendo un uso extensivo de boost:shared_ptr en mi código. De hecho, la mayoría de los objetos que están asignados en el montón están en un shared_ptr. Desafortunadamente, esto significa que no puedo pasar this a ninguna función que tome shared_ptr. Considere este código:Obteniendo un impulso :: shared_ptr para este

void bar(boost::shared_ptr<Foo> pFoo) 
{ 
    ... 
} 

void Foo::someFunction() 
{ 
    bar(this); 
} 

Aquí hay dos problemas. Primero, esto no se compilará porque el constructor T * para shared_ptr es explícito. En segundo lugar, si lo forzo a construir con bar(boost::shared_ptr<Foo>(this)), he creado un segundo puntero compartido para mi objeto que eventualmente conducirá a una eliminación doble.

Esto me lleva a mi pregunta: ¿Hay algún patrón estándar para obtener una copia del puntero compartido existente que usted conoce que existe dentro de un método en uno de esos objetos? ¿El uso de referencia intrusiva es mi única opción aquí?

+0

"_Is utilizando referencia intrusiva contando mi única opción aquí _ "¿Qué pasa con esta opción? – curiousguy

+0

Quizás nada. Depende de tus circunstancias. Hace tus objetos más grandes y puede que no funcionen en lugares donde no tienes control sobre las clases a las que mandas a los smartpointers. –

+0

enabe_shared_from_this ahora está en 'std ::'. Eche un vistazo a mi respuesta. –

Respuesta

102

Usted puede derivar de enable_shared_from_this y luego se puede utilizar "shared_from_this()" en lugar de "esto" para desovar un puntero compartido a su propio objeto.

ejemplo, en el enlace:

#include <boost/enable_shared_from_this.hpp> 

class Y: public boost::enable_shared_from_this<Y> 
{ 
public: 

    shared_ptr<Y> f() 
    { 
     return shared_from_this(); 
    } 
} 

int main() 
{ 
    shared_ptr<Y> p(new Y); 
    shared_ptr<Y> q = p->f(); 
    assert(p == q); 
    assert(!(p < q || q < p)); // p and q must share ownership 
} 

Es una buena idea cuando desove hilos de una función miembro para impulsar :: unen a un shared_from_this() en lugar de esto. Garantizará que el objeto no se libere.

+0

f() es como ". Copiar()" y también es una copia superficial. –

9

¿Realmente está haciendo más copias compartidas de pFoo inside bar? Si usted no está haciendo nada loco dentro, sólo hacer esto:


void bar(Foo &foo) 
{ 
    // ... 
} 
3

La función de aceptar un puntero quiere hacer una de dos comportamientos:

  • el propietario del objeto que se pasa en, y elimínelo cuando salga del alcance. En este caso, puede aceptar X * e inmediatamente ajustar un scoped_ptr alrededor de ese objeto (en el cuerpo de la función). Esto funcionará para aceptar "esto" o, en general, cualquier objeto asignado en el montón.
  • Compartir un puntero (no lo tienen) para el objeto que se ha pasado. En este caso lo hace no desee utilizar un scoped_ptr en absoluto, ya que no desea eliminar el objeto en el fin de tu función En este caso, lo que teóricamente quieres es un shared_ptr (lo he visto llamar un linked_ptr en otro lugar). La biblioteca de impulso tiene a version of shared_ptr, y esto también se recomienda en el libro Efectivo C++ de Scott Meyers (elemento 18 en la 3ª edición).

Editar: Vaya poco leí mal la pregunta, y ahora veo que esta respuesta no se dirige exactamente la pregunta. Lo dejaré de todos modos, en caso de que esto pueda ser útil para cualquiera que trabaje con código similar.

19

Simplemente use un puntero sin formato para su parámetro de función en lugar del shared_ptr. El objetivo de un puntero inteligente es controlar la duración del objeto, pero la duración del objeto ya está garantizada por las reglas de determinación del alcance de C++: existirá al menos hasta el final de su función.Es decir, el código de llamada no puede eliminar el objeto antes de que regrese su función; por lo tanto, la seguridad de un puntero "tonto" está garantizada, siempre y cuando no intente eliminar el objeto dentro de su función.

La única vez que necesita pasar un shared_ptr a una función es cuando desea pasar la propiedad del objeto a la función o desea que la función haga una copia del puntero.

+1

De acuerdo. Muchas veces puedes usar foo (const Object * object_ptr) {} foo (obj.get()); donde obj es un impulso :: shared_ptr < Object >. Busque en la web a Herb Sutter, es otro escritor de artículos que tiene mucha información sobre este y otros temas similares. –

+1

No viene nada al caso, pero ... Si puede usar el puntero, entonces (lo más probable) puede usar la referencia, que es mejor IMO. –

+1

@ denis-bu, excepto cuando un puntero 'NULL' es una posibilidad. Pero tú haces un buen punto. –

5

Con C++ 11 shared_ptr y enable_shared_from_this ahora está en la biblioteca estándar. El último es, como su nombre lo sugiere, para este caso exactamente.

http://en.cppreference.com/w/cpp/memory/shared_ptr

http://en.cppreference.com/w/cpp/memory/enable_shared_from_this

Ejemplo bases en que en los enlaces de arriba:

struct Good: std::enable_shared_from_this<Good>{ 
    std::shared_ptr<Good> getptr() { 
     return shared_from_this(); 
    } 
}; 

uso:?

std::shared_ptr<Good> gp1(new Good); 
std::shared_ptr<Good> gp2 = gp1->getptr(); 
std::cout << "gp2.use_count() = " << gp2.use_count() << '\n'; 
Cuestiones relacionadas