Pregunta

Estoy haciendo un uso extensivo de boost:shared_ptr en mi código.De hecho, la mayoría de los objetos que se asignan en el montón están retenidos por un shared_ptr.Desafortunadamente esto significa que no puedo pasar. this en cualquier función que requiera un shared_ptr.Considere este código:

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

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

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

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

¿Fue útil?

Solución

Puede derivar de enable_shared_from_this y luego usted puede usar " shared_from_this () " en lugar de " esto " para generar un puntero compartido a su propio objeto propio.

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 se generan hilos de una función miembro para impulsar :: bind a shared_from_this () en lugar de esto. Se asegurará de que el objeto no se libere.

Otros consejos

Simplemente use un puntero sin formato para su parámetro de función en lugar de shared_ptr. El propósito de un puntero inteligente es controlar la vida útil del objeto, pero la vida útil del objeto ya está garantizada por las reglas de 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; así la seguridad de un & "; tonto &"; el puntero está garantizado, siempre que no intente eliminar el objeto dentro de su función.

El único momento en 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.

boost tiene una solución para este caso de uso, marque enable_shared_from_this

¿Realmente estás haciendo más copias compartidas de pFoo dentro de la barra? Si no estás haciendo nada loco por dentro, solo haz esto:


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

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

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

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

El ejemplo se basa en eso en los enlaces anteriores:

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

usar:

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

La función que acepta un puntero quiere hacer uno de dos comportamientos:

  • Poseer el objeto que se pasa y eliminarlo cuando salga del alcance. En este caso, puede aceptar X * e inmediatamente envolver un scoped_ptr alrededor de ese objeto (en el cuerpo de la función). Esto funcionará para aceptar & Quot; this & Quot; o, en general, cualquier objeto asignado en el montón.
  • Comparta un puntero (no lo posee) al objeto que se pasa. En este caso, no desea utilizar un scoped_ptr, ya que no desea eliminar el objeto al final de su función. En este caso, lo que teóricamente quieres es un shared_ptr (lo he visto llamado un enlace_ptr en otro lugar). La biblioteca de impulso tiene una versión de shared_ptr , y esto también se recomienda en el eficaz libro de C ++ de Scott Meyers (ítem 18 en la 3ra edición).

Editar: ¡Vaya! Leí un poco la pregunta y ahora veo que esta respuesta no responde exactamente a la pregunta. Lo dejaré de todos modos, en caso de que esto pueda ser útil para cualquier persona que trabaje en un código similar.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top