c++ - sobre - juegos de preguntas y test
preguntas relacionadas con compartir_de_ esto (5)
Tengo una función que toma un shared_ptr<MyClass>
. En alguna función miembro memfun
de MyClass
, necesito pasar this
a esa función. Pero si escribo
void MyClass:memfun()
{
func(shared_ptr<MyClass>(this))
}
Supongo que después de que la llamada haya finalizado, el recuento de referencias alcanzará 0 y se intentará destruirlo, lo cual es malo.
Entonces recordé que existe esta clase enable_shared_from_this
con la función shared_from_this
.
Así que ahora voy a usar lo siguiente:
class MyClass: public enable_shared_from_this<MyClass>
{
void MyClass:memfun()
{
func(shared_from_this());
}
};
Las preguntas son:
1) ¿Es absolutamente imposible usar la funcionalidad sin derivar de enable_shared_from_this
?
2) ¿ enable_shared_from_this
de enable_shared_from_this
significa que llamar a memfun en un objeto con duración de almacenamiento automático resultará en algo malo? P.ej
int main()
{
MyClass m; //is this OK?
m.memfun(); // what about this?
}
3) Si derivo de MyClass, ¿la funcionalidad enable_shared_from_this se heredará correctamente o debo derivar de nuevo? Es decir,
class MyCoolClass: public Myclass
{
void someCoolMember
{
someCoolFuncTakingSharedPtrToMyCoolClass(shared_from_this());
}
}
¿Esta bien? O lo correcto es lo siguiente?
class MyCoolClass: public Myclass, public enable_shared_from_this<MyCoolClass>
{
void someCoolMember
{
someCoolFuncTakingSharedPtrToMyCoolClass(enable_shared_from_this<MyCoolClass>::shared_from_this());
}
}
Muchas gracias de antemano.
1) Depende de lo que quieras decir con "haz esto" para saber si puedes o no. Siempre puede construir un shared_ptr
partir de un puntero en bruto como this
, pero no compartirá el recuento de referencia con otra instancia de shared_ptr
que se construyó por separado a partir de un puntero en bruto. Por lo tanto, tendrá que usar un eliminador personalizado en una u otra instancia para evitar dobles eliminaciones, pero a menos que tenga mucho cuidado, puede terminar con colgantes shared_ptr
instancias debido a que el objeto se elimina a través de una, pero sigue siendo accesible desde otra.
shared_from_this
permite garantizar que si tiene una instancia de shared_ptr
en su objeto, puede construir otra sin copiar la primera, y que estas instancias compartirán el recuento de referencias. Podría lograrlo almacenando un valor weak_ptr
como miembro de la clase y estableciendo ese valor cuando asigne por primera vez un objeto shared_ptr
a su objeto.
2) Para llamar a shared_from_this()
requiere que al menos una instancia de shared_ptr
ya apunte a su objeto. Si lo usa en un objeto automático sin una instancia de shared_ptr
con un eliminador personalizado, entonces ocurrirán cosas malas.
3) Si se deriva de su clase, la funcionalidad enable_shared_from_this
le dará un shared_ptr
a la clase base (la que deriva de enable_shared_from_this
). Luego podría usar static_pointer_cast
o dynamic_pointer_cast
para convertir el resultado de shared_from_this()
a un puntero a la clase derivada.
Además con David Rodríguez - dribeas, el puntero compartido no es recomendado por google
Mantiene el recuento de referencias internamente, por lo que, para que funcione correctamente, se utilizan InterlockedIncrement y InterlockedDecrement, estas dos funciones son realmente más lentas que las normales ++ y -.
Debe comprobar que la propiedad de este objeto realmente deba compartirse con otros, según mi experiencia, el puntero compartido podría evitarse en la mayoría de los casos.
La pregunta importante aquí es por qué la función toma el argumento a través de shared_ptr
. ¿Almacena el puntero internamente para su uso posterior? ¿Solo se usa durante la duración de la llamada? ¿Por qué se diluye la propiedad entre la persona que llama y la persona que llama?
Algunas respuestas sugieren que proporcione un eliminador no operativo si va a pasar un objeto asignado a la pila a la función, pero si la función está almacenando realmente el shared_ptr
para su uso posterior, podría ser el caso que para el momento en que se encuentre para ello, el objeto asignado localmente ya no está en la pila y se dispara UB. Tener el no-op deleter shared_ptr
permitirá la llamada, pero la semántica no será correcta.
Si la función no almacena el shared_ptr
para su uso posterior, ¿cuál fue la decisión de diseño que condujo a esa API? Si puede cambiar la función (y no hay un motivo inminente), shared_ptr
recibir el argumento por referencia y tendrá una interfaz más amigable que no impone un shared_ptr
sin ningún motivo.
Si al final determina que puede garantizar que el objeto en la pila estará vivo durante toda la duración del proceso desencadenado por esa llamada a la función, entonces y solo entonces use el eliminador de no-op.
Si tiene un objeto con almacenamiento automático y una función que requiere shared_ptr y sabe que la vida útil de su objeto será lo suficientemente larga para la duración de la función y que no almacena el shared_ptr en ningún lugar, entonces puede pasarlo con una no-op deleter.
Esto es útil para objetos estáticos. Si realmente tiene almacenamiento automático local, debe preguntarse por qué la función está tomando shared_ptr. ¿Los guarda?
Hay otro constructor menos conocido para shared_ptr para un objeto que es miembro de otro objeto con cuenta de referencia. Realmente puede crear un shared_ptr con el shared_ptr desde el objeto externo y el puntero desde el objeto interno.
1) No, no es imposible hacer esto sin shared_from_this
. Simplemente puede construir un shared_ptr
con un shared_ptr
no-op:
void do_nothing(MyClass*) {}
void MyClass:memfun()
{
func(shared_ptr<MyClass>(this, do_nothing));
}
Al ver que no parece que realmente necesites shared_from_this
esto, voy a omitir las siguientes dos partes de tu pregunta.