Pregunta

Me encontré con enable_shared_from_this durante la lectura de los ejemplos Boost.Asio y después de leer la documentación Todavía estoy perdido de cómo esto correctamente se debe utilizar. Por favor alguien puede darme un ejemplo y / o y explicación de cuando se utiliza esta clase tiene sentido.

Otros consejos

Dr. Dobbs del artículo sobre los punteros débiles, creo que este ejemplo es más fácil de entender (fuente: http: // drdobbs .com / CPP / 184402026 ):

... código como este no funcionará correctamente:

int *ip = new int;
shared_ptr<int> sp1(ip);
shared_ptr<int> sp2(ip);

Ninguno de los dos objetos shared_ptr sabe acerca de la otra, por lo tanto se trate de liberar el recurso cuando son destruidos. Que por lo general conduce a problemas.

Del mismo modo, si una función miembro necesita un objeto shared_ptr que posee el objeto que está siendo llamado en adelante, puede no sólo crear un objeto sobre la marcha:

struct S
{
  shared_ptr<S> dangerous()
  {
     return shared_ptr<S>(this);   // don't do this!
  }
};

int main()
{
   shared_ptr<S> sp1(new S);
   shared_ptr<S> sp2 = sp1->dangerous();
   return 0;
}

Este código tiene el mismo problema que el ejemplo anterior, aunque en una forma más sutil. Cuando se construyó, la shared_pt objeto sp1r posee el recurso recién asignada. El código dentro de la función miembro S::dangerous no sabe nada de ese objeto shared_ptr, por lo que el objeto shared_ptr que devuelve es distinta de sp1. Copiar el nuevo objeto shared_ptr a sp2 no ayuda; cuando sp2 sale del ámbito, se dará a conocer el recurso, y cuando sp1 sale del ámbito, se dará a conocer el recurso de nuevo.

La forma de evitar este problema es utilizar el enable_shared_from_this plantilla de clase. La plantilla toma un argumento tipo de plantilla, que es el nombre de la clase que define el recurso gestionado. Esa clase debe, a su vez, puede derivar públicamente a partir de la plantilla; de esta manera:

struct S : enable_shared_from_this<S>
{
  shared_ptr<S> not_dangerous()
  {
    return shared_from_this();
  }
};

int main()
{
   shared_ptr<S> sp1(new S);
   shared_ptr<S> sp2 = sp1->not_dangerous();
   return 0;
}

Al hacer esto, tenga en cuenta que el objeto sobre el que se llama a shared_from_this debe ser propiedad de un objeto shared_ptr. Esto no funcionará:

int main()
{
   S *p = new S;
   shared_ptr<S> sp2 = p->not_dangerous();     // don't do this
}

Aquí está mi explicación, desde una perspectiva de tuercas y pernos (respuesta no superior 'clic' conmigo). * Tenga en cuenta que este es el resultado de la investigación de la fuente de shared_ptr y enable_shared_from_this que viene con Visual Studio 2012. Tal vez otros compiladores implementan de forma diferente ... * enable_shared_from_this

enable_shared_from_this<T> agrega una instancia weak_ptr<T> privado a T que mantiene el ' una verdadera referencia recuento ' para la instancia de T.

Por lo tanto, cuando se crea un shared_ptr<T> en una nueva T *, que weak_ptr interna T * 's se inicializa con un refcount de 1. El nuevo shared_ptr básicamente se mete hacia esta weak_ptr.

T puede entonces, en sus métodos, llamar shared_from_this para obtener una instancia de shared_ptr<T> que respalda a la misma referencia almacenado internamente recuento . De esta manera, siempre tendrá un lugar en el ref-recuento de T* se almacena en lugar de tener varias instancias shared_ptr que no saben el uno del otro, y cada uno piensa que son la shared_ptr que está a cargo de T ref-conteo y elimine cuando su ref-cuenta llega a cero.

Tenga en cuenta que el uso de un impulso :: intrusive_ptr no sufre de este problema. Esto es a menudo una manera más conveniente de conseguir alrededor de este problema.

Es exactamente lo mismo en C ++ 11 y más adelante:. Es para que la capacidad de volver this como un puntero compartida desde this le da un puntero prima

en otras palabras, que le permita activar un código como éste

class Node {
public:
    Node* getParent const() {
        if (m_parent) {
            return m_parent;
        } else {
            return this;
        }
    }

private:

    Node * m_parent = nullptr;
};           

en esto:

class Node : std::enable_shared_from_this<Node> {
public:
    std::shared_ptr<Node> getParent const() {
        std::shared_ptr<Node> parent = m_parent.lock();
        if (parent) {
            return parent;
        } else {
            return shared_from_this();
        }
    }

private:

    std::weak_ptr<Node> m_parent;
};           

Otra forma es añadir un miembro weak_ptr<Y> m_stub en el class Y. A continuación, escriba:

shared_ptr<Y> Y::f()
{
    return m_stub.lock();
}

Útil cuando no se puede cambiar la clase que se derivan de (que se extiende por ejemplo, biblioteca de otras personas). No se olvide de inicializar el miembro de, por ejemplo, por m_stub = shared_ptr<Y>(this), su es válida incluso durante un constructor.

Está bien si hay más talones como ésta en jerarquía de herencia, no va a evitar la destrucción del objeto.

Editar: Como correctamente señalado por Nobar usuario, el código destruiría objeto Y cuando la asignación está terminado y variables temporales son destruidos. Por lo tanto, mi respuesta es incorrecta.

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