preguntas sobre compartido de este
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))
}
Asumo que después de que la llamada haya terminado, el recuento de referencias alcanzará 0 y this
se intentará destruir, lo cual es malo.
Entonces recordé que hay esta clase enable_shared_from_this
con la función shared_from_this
.
Así que ahora voy a usar lo siguiente: {[15]]}
class MyClass: public enable_shared_from_this<MyClass>
{
void MyClass:memfun()
{
func(shared_from_this());
}
};
Preguntas son:
1) ¿Es absolutamente imposible utilizar la funcionalidad sin derivar de enable_shared_from_this
?
2) ¿Derivar de enable_shared_from_this
significa que llamar a memfun en un objeto con duración de almacenamiento automático resultará en algo malo? Por ejemplo,
int main()
{
MyClass m; //is this OK?
m.memfun(); // what about this?
}
3) Si derivo de MyClass, ¿se heredará correctamente la funcionalidad enable_shared_from_this o necesito derivar de nuevo? Es decir,
class MyCoolClass: public Myclass
{
void someCoolMember
{
someCoolFuncTakingSharedPtrToMyCoolClass(shared_from_this());
}
}
¿Esto está bien? O correcto es el ¿siguiendo?
class MyCoolClass: public Myclass, public enable_shared_from_this<MyCoolClass>
{
void someCoolMember
{
someCoolFuncTakingSharedPtrToMyCoolClass(enable_shared_from_this<MyCoolClass>::shared_from_this());
}
}
Muchas Gracias por adelantado.
5 answers
1) Depende de lo que quieres decir con "haz esto"en cuanto a si puedes o no. Siempre puede construir un shared_ptr
a partir de un puntero raw como this
, pero no compartirá el recuento de referencias con otra instancia shared_ptr
que se construyó por separado a partir de un puntero raw. Por lo tanto, necesitará usar un deleter personalizado en una u otra instancia para evitar eliminaciones dobles, pero a menos que tenga mucho cuidado, puede terminar con instancias colgando shared_ptr
debido a que el objeto se elimina a través de una, pero aún así accesible desde otro.
shared_from_this
le permite garantizar que si tiene una instancia shared_ptr
en su objeto, puede construir otra sin copiar la primera, y que estas instancias compartirán el recuento de referencias. Podría lograr esto almacenando un weak_ptr
como miembro de la clase, y estableciendo ese valor cuando asigne por primera vez un shared_ptr
a su objeto.
2) Llamar a shared_from_this()
requiere que haya al menos una instancia shared_ptr
ya apuntando a su objeto. Si lo usa en un objeto automático sin una instancia shared_ptr
con un deleter personalizado, entonces obtendrá cosas malas sucediendo.
3) Si derivas de tu clase entonces la funcionalidad enable_shared_from_this
te dará un shared_ptr
a la clase base (la que derivó de enable_shared_from_this
). Entonces 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.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-27 09:56:22
La pregunta importante aquí es por qué la función toma el argumento a través de un shared_ptr
. ¿Almacena el puntero internamente para su uso posterior? ¿Solo lo utiliza durante la duración de la llamada? ¿Por qué se diluye la propiedad entre la persona que llama y el destinatario?
Algunas respuestas sugieren que proporcione un deleter no-op si va a pasar un objeto asignado a la pila a la función, pero si la función está almacenando el shared_ptr
para su uso posterior, podría ser el caso de que en el momento en que se acerca a él, el objeto asignado localmente ya no está en la pila y se activa UB. Tener el deleter no-op 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 llevó a esa API? Si puede cambiar la función (y no hay ninguna razón inminente), haga que reciba el argumento por referencia y tendrá una interfaz más amigable que no impone un shared_ptr
para no 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 deleter no-op.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-08 13:40:14
1) no, no es imposible hacer esto sin shared_from_this
. Simplemente puede construir un shared_ptr
con un deleter no-op:
void do_nothing(MyClass*) {}
void MyClass:memfun()
{
func(shared_ptr<MyClass>(this, do_nothing));
}
Viendo que en realidad no parece necesitar shared_from_this
después de todo, voy a omitir las siguientes dos partes de su pregunta.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-08 13:11:58
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 un deleter no-op.
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 almacena?
Hay otro constructor menos conocido a shared_ptr para un objeto que es miembro de otro objeto contado por referencia. En realidad, puede crear un shared_ptr con el shared_ptr del objeto externo y el puntero del objeto interno.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-08 13:14:06
Además de David Rodríguez-dribeas, el puntero compartido no es recomendado por google
Mantiene el recuento de referencia internamente, por lo que para que funcione correctamente, se utilizan InterlockedIncrement y InterlockedDecrement, estas dos funciones son realmente más lentas que normal ++ y --.
Debe comprobar que la propiedad de este objeto realmente necesita ser compartida con otros, según mi experiencia, el puntero compartido podría evitarse en la mayoría de los casos.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-30 09:16:26