Pasar punteros compartidos como argumentos


Si declaro un objeto envuelto en un puntero compartido:

std::shared_ptr<myClass> myClassObject(new myClass());

Entonces quería pasarlo como argumento a un método:

DoSomething(myClassObject);

//the called method
void DoSomething(std::shared_ptr<myClass> arg1)
{
   arg1->someField = 4;
}

¿Lo anterior simplemente incrementa el recuento de referencias de shared_pt y todo está bien? ¿O deja un puntero colgando?

¿Todavía se supone que debes hacer esto?:

DoSomething(myClassObject.Get());

void DoSomething(std::shared_ptr<myClass>* arg1)
{
   (*arg1)->someField = 4;
}

Creo que la 2a manera puede ser más eficiente porque solo tiene que copiar 1 dirección( en lugar de todo el puntero inteligente), pero la 1a manera parece más legible y no preveo empujar los límites de rendimiento. Sólo quiero asegurarme de que no hay nada peligroso en ello.

Gracias.

Author: R. Martinho Fernandes, 2012-05-31

4 answers

Quiero pasar un puntero compartido a una función. ¿Puedes ayudarme con eso?

Claro, puedo ayudarte con eso. Asumo que tiene algún conocimiento de la semántica de propiedad en C++. Es eso cierto?

Sí, estoy razonablemente cómodo con el tema.

Bien.

Ok, solo puedo pensar en dos razones para tomar un shared_ptr argumento:

  1. La función quiere compartir la propiedad del objeto;
  2. La función hace alguna operación que funciona específicamente en shared_ptr s.

¿En cuál estás interesado?

Estoy buscando una respuesta general, así que en realidad estoy interesado en ambos. Tengo curiosidad sobre lo que quieres decir en el caso # 2, sin embargo.

Ejemplos de tales funciones incluyen std::static_pointer_cast, comparadores personalizados o predicados. Por ejemplo, si necesita encontrar todo shared_ptr único de un vector, necesita dicho predicado.

Ah, cuando la función en realidad necesita manipular el puntero inteligente en sí.

Exactamente.

En ese caso, creo que deberíamos pasar por referencia.

Sí. Y si no cambia el puntero, desea pasar por referencia const. No es necesario copiar, ya que no es necesario compartir la propiedad. Ese es el otro escenario.

Ok, lo tengo. Hablemos del otro escenario.

¿El que comparte la propiedad? Ok. Cómo compartir propiedad con shared_ptr?

Copiándolo.

Entonces la función tendrá que hacer una copia de un shared_ptr, ¿correcto?

Obviamente. Así que lo paso por una referencia a const y copiar a una variable local?

No, eso es una pesimización. Si se pasa por referencia, la función no tendrá más remedio que hacer la copia manualmente. Si se pasa por valor, el compilador elegirá la mejor opción entre una copia y un movimiento y lo realizará automática. Por lo tanto, pasar por valor.

Buen punto. Debo recordar que " ¿Quieres velocidad? Pase por Valor." artículo más a menudo.

Espere, ¿qué pasa si la función almacena el shared_ptr en una variable miembro, por ejemplo? ¿Eso no hará una copia redundante?

La función puede simplemente mover el argumento shared_ptr a su almacenamiento. Mover un shared_ptr es barato porque no cambia ningún recuento de referencia.

Ah, buena idea.

Pero Estoy pensando en un tercer escenario: ¿qué pasa si no quieres manipular el shared_ptr, ni compartir la propiedad?

En ese caso, shared_ptr es completamente irrelevante para la función. Si desea manipular el punzón, tome un punzón y deje que las personas que llaman elijan qué semántica de propiedad desean.

¿Y debo tomar el puntito por referencia o por valor?

Se aplican las reglas habituales. Los punteros inteligentes no cambian nada.

Pasar por valor si voy a copiar, pase por referencia si quiero evitar una copia.

Correcto.

Hmm. Creo que olvidaste otro escenario. ¿Qué pasa si quiero compartir la propiedad, pero solo dependiendo de una determinada condición?

Ah, un caso interesante. No espero que eso suceda a menudo. Pero cuando sucede, puede pasar por valor e ignorar la copia si no la necesita, o pasar por referencia y hacer la copia si la necesita.

I arriesgue una copia redundante en la primera opción y pierda un movimiento potencial en la segunda. ¿No puedo comer el pastel y comerlo también?

Si se encuentra en una situación en la que eso realmente importa, puede proporcionar dos sobrecargas, una tomando una referencia const lvalue y otra tomando una referencia rvalue. Una copia, la otra se mueve. Una plantilla de función de reenvío perfecto es otra opción.

Creo que eso cubre todos los escenarios posibles. Muchas gracias.

 141
Author: R. Martinho Fernandes,
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
2017-04-12 15:57:50

Creo que la gente está innecesariamente asustada de usar punteros raw como parámetros de función. Si la función no va a almacenar el puntero o afectar su vida útil, un puntero raw funciona igual de bien y representa el mínimo común denominador. Considere, por ejemplo, cómo pasaría un unique_ptr en una función que toma un shared_ptr como parámetro, ya sea por valor o por referencia const?

void DoSomething(myClass * p);

DoSomething(myClass_shared_ptr.get());
DoSomething(myClass_unique_ptr.get());

Un puntero raw como parámetro de función no le impide usar punteros inteligentes en el código de llamada, donde realmente importa.

 14
Author: Mark Ransom,
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
2012-05-31 03:39:22

Sí, la idea completa sobre un shared_ptr es que varias instancias pueden contener el mismo puntero raw y la memoria subyacente solo se liberará cuando se destruya la última instancia de shared_ptr.

Evitaría un puntero a un shared_ptr ya que eso frustra el propósito ya que ahora está tratando con raw_pointers nuevamente.

 3
Author: R Samuel Klatchko,
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
2012-05-31 02:07:16

Pasar por valor en su primer ejemplo es seguro, pero hay un mejor modismo. Pasar por referencia const cuando sea posible-yo diría que sí, incluso cuando se trata de punteros inteligentes. Su segundo ejemplo no está exactamente roto, pero es muy !???. Tonto, no lograr nada y derrota parte del punto de punteros inteligentes, y va a dejarte en un buggy mundo de dolor cuando trates de desreferenciar y modificar las cosas.

 2
Author: djechlin,
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
2012-05-31 02:07:24