Pregunta

Las referencias en C ++ son una construcción de convenio que nos permite simplificar el siguiente código C:

f(object *p){
  //do something
}

int main(){
  object* p = (object*) calloc(sizeof(object));
  f(p);
}

a

f(object& o){
  //do something
}

int main(){
  object o = object();
  f(o);
}

Los punteros compartidos son otra conveniencia en C ++ que simplifica la administración de la memoria. Sin embargo, no estoy seguro de cómo pasar un shared_ptr a una función como f (object & amp; o) , ¿cuál acepta los argumentos por referencia?

f(object& o){
  //do something
}

int main(){
  shared_ptr<object> p (new object());
  f(*p);
}

¿Se incrementará el puntero compartido cuando su objeto se pase por referencia a una función?

¿Fue útil?

Solución

Tome un shared_ptr por valor, y el recuento de referencia aumentará. Esto es más fácil cuando typedef it:

typedef boost:shared_ptr<object> object_ptr;

void foo(object_ptr obj)
{
    obj->/* stuff*/;
    obj.reset(); //only resets this local copy, that means:
                 // reduce reference count (back to 1), and
                 // set obj to point at null.
}

int main(void)
{
    object_ptr obj(new object());
    foo(obj);
}

Ten en cuenta que las referencias son alias. Cuando pasa por referencia, no está pasando punteros, copias, etc ..., está creando un alias de otro objeto. (En realidad se implementan como punteros):

typedef boost:shared_ptr<object> object_ptr;

void foo(object_ptr& obj)
{
    obj.reset(); // the references was never increased, since a copy has not
                 // been made, this *is* obj in main. so the reference 
                 // goes to 0, and obj is deleted
}

int main(void)
{
    object_ptr obj(new object);
    foo(obj); // after this, obj has been reset!
}

Siempre recuerde estar const correcto, para evitar errores:

typedef boost:shared_ptr<object> object_ptr;

void foo(const object_ptr& obj)
{
    obj.reset(); // cannot do! 
}

int main(void)
{
    object_ptr obj(new object);
    foo(obj);
}

Creo que debería preferir pasar punteros inteligentes como referencias cuando sea posible, para evitar incrementos y decrementos extraños (y copias y todo eso).

Otros consejos

  

¿Se incrementará el puntero compartido cuando su objeto se pase por referencia a una función?

No, ya que está accediendo al puntero en bruto y luego lo pasa. Quieres hacer algo similar a esto:

f(shared_ptr<object> o){
  //do something
}

int main(){
  shared_ptr<object> p (new object());
  f(p);
}
f(object& o){
  //do something
}

int main(){
  shared_ptr<object> p (new object());
  f(*p);
}
     

Se incrementará el puntero compartido   cuando su objeto se pasa por referencia   a una función?

En el código de arriba - no. p tendrá su contador de referencia igual a 1 en todo momento. Puedes verificar esto en un depurador. El contador de referencia de shared_ptr cuenta el número de instancias de shared_ptr que apuntan al mismo objeto, no rastrea las referencias que creas llamando al operador * (). Y no tiene que hacerlo, ya que se garantiza que p se mantendrá hasta el final del alcance y la llamada a la función se encuentra en este mismo alcance (o más profundo) p será durante toda la llamada a f (). Así que todo está bien.

... a menos que en f tome la dirección de o y almacene en algún lugar que dure después de que f regrese. Esto debe evitarlo por todos los medios: pase el shared_ptr si necesita hacerlo.

Lo primero es lo primero, desde el punto de vista de la funcionalidad, las referencias en C ++ son exactamente lo mismo que los punteros. La única razón por la que se agregaron al lenguaje fue para hacer que la sintaxis de la sobrecarga de operadores fuera más natural. (Por ejemplo, para permitir que se escriba a + b en lugar de & amp; a + & amp; b)

Sus ejemplos de código C y C ++ no son en absoluto equivalentes. La versión C de tu código C ++ sería:

f(object *p){
  //do something
}

int main(){
  object o;
  object_constructor(&o);
  f(&o);
  object_destructor(&o);
}

De hecho, este es el tipo de código que generará conceptualmente el compilador de C ++.

Con respecto a su segunda pregunta: Sí, esa es la forma correcta de llamar a la función f. El contador de puntero compartido no se incrementará. Se pasará el puntero real al objeto, como si no estuviera usando una shared_ptr. Sin embargo, es seguro, siempre y cuando f no esté haciendo nada funky. Solo recuerde que exactamente lo mismo está sucediendo como si el parámetro de f tomara un puntero en lugar de una referencia. La única diferencia es que el compilador pasa automáticamente la dirección de la variable sin que tenga que usar explícitamente el & amp; operador.

Personalmente, no me gusta pasar las variables por referencia (aunque el paso por referencia constante está bien). Prefiero usar un puntero, ya que deja más claro en el sitio de la llamada que la función que estamos llamando podría modificar su argumento (ya que el símbolo & amp; es visible en el sitio de la llamada).

Paz

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