¿Hay alguna ventaja de usar std :: unique_ptr y en lugar de std :: unique_ptr ?

¿Hay alguna ventaja de usar std::unique_ptr& lugar de std::unique_ptr ? Por ejemplo, en argumentos de función?

std :: unique_ptr solo se puede mover, por lo que si pasa unique_ptr por valor, no podrá extraer su contenido después de la llamada a la función, pero si pasa por referencia, se puede recuperar el valor. A continuación se muestra código de ejemplo para el mismo:

 #include  #include  void changeUniquePtrReference(std::unique_ptr& upr) { *upr = 9; } void changeUniquePtrValue(std::unique_ptr upv) { *upv = 10; } int main() { std::unique_ptr p(new int); *p =8; std::cout<<"value of p is "<<*p< 

Hay algunas situaciones diferentes

  1. Quieres transferir la propiedad a la función.
    • Utilice std::unique_ptr
  2. Quieres permitir que la función modifique el puntero.
    • Use std::unique_ptr &
  3. Quieres permitir que la función modifique el pointee.
    • Use T & y desreferencia en el sitio de la llamada
    • Si el puntero puede ser nulo, use T * y llame a unique_ptr::get en el sitio de la llamada
  4. Quieres permitir que la función observe al pointee.
    • Use const T & y desreferencia en el sitio de la llamada
    • Si el puntero puede ser nulo, en su lugar use const T * y llame a unique_ptr::get en el sitio de la llamada
  5. Quieres permitir que la función tenga una copia del pointee
    • Use T , y desreferencia en el sitio de la llamada
  6. Tiene un bucle de rango (o ) sobre una colección de unique_ptr y desea observar los valores y no tiene ranges::indirect (o similar )
    • Use auto & , y sepa que se infiere como std::unique_ptr & (o const std::unique_ptr & si la colección es const ), por lo que debe desreferenciarse en el cuerpo del bucle

Como std::unique_ptr no se puede copiar por diseño, una función que toma std::unique_ptr solo puede invocarse pasando la propiedad del puntero a la función (es decir, mover construcción). El código de llamada ya no podrá acceder al puntero.

Al usar std::unique_ptr& , está permitiendo que la función “vea” el puntero y acceda a su miembro, pero el código de llamada conserva la propiedad, por lo que aún podrá usarlo.

Las dos variantes son diferentes y se aplican en situaciones específicas.

Si su función toma std::unique_ptr , esto significa que toma posesión del objeto administrado y lo eliminará o guardará en otro lugar.

Si toma std::unique_ptr & , no toma posesión, pero puede cambiar a lo que apunta el puntero, por ejemplo, restableciéndolo a un objeto diferente.

Si no planea cambiar el puntero en sí, simplemente pasaría una T& , o una const T& , dependiendo de si planea modificar el objeto. No es útil pasar const std::unique_ptr & ya que eso no le permite hacer más que con T& , con las desventajas de una posible indirección adicional y una restricción innecesaria en el argumento.

Herb Sutter explica todos los inconvenientes y ventajas de pasar punteros inteligentes a funciones con todas las variaciones posibles. Por favor, lea el artículo para más información, es realmente bueno:

En resumen, no tiene sentido pasar el unique_ptr a la función sin referencia, a menos que su comportamiento pretendido sea renunciar a la propiedad del puntero.

Personalmente, veo un solo caso en el que debe pasar una referencia a unique_ptr: es cuando el método al que llama puede decidir internamente eliminar el objeto o abandonarlo. Esto debería ser muy raro, ya que el propietario renuncia a la decisión sobre la propiedad y, honestamente, no es un gran diseño.

Si el objeto secundario siempre quita la propiedad o elimina el objeto, el tipo de argumento debería ser un valor unique_ptr y pasar la propiedad inmediatamente.

Si el objeto hijo simplemente quiere acceder al contenido del puntero, entonces el argumento debería ser un puntero en bruto . Puede hacer un argumento para una const unique_ptr reference que le impida liberarlo, pero ¿cuál es el punto? Puede decorar el nombre del tipo de puntero en bruto para que sepa que no lo posee, si cree que necesita una convención más allá del en bruto.