es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Comprendiendo el movimiento semántico para un shared_ptr con una llamada de función rvalue.

En el siguiente programa pequeño tengo dos ejemplos de uso de move con shared_ptr.

El primer ejemplo se comporta como esperaba y la propiedad del shared_ptr p se le asigna al nuevo puntero p2. Después de la asignación, p es un puntero inválido.

Esperaría que lo mismo suceda también en el segundo ejemplo, pero no lo hace. Las preguntas precisas están incrustadas como comentarios en el código fuente. ¿Qué está mal en mi razonamiento?

“`cpp
#include <memory>
#include <iostream>
using namespace std;

void foo(shared_ptr<int>&& p)
{
std::cout << "zoo: " << p.use_count() << "\n";
// cuando esta función termina, ¿el destructor de p debería
// decrementar el contador de referencias y destruir el objeto apuntado?
}

void example1()
{
auto p = make_shared<int>(0);
std::cout << "count before move: " << p.use_count() << "\n";
shared_ptr<int> p2(move(p));
std::cout << "count after move: " << p.use_count() << "\n"; // output 0: propiedad transferida a p2
}

void example2()
{
auto p = make_shared<int>(0);
std::cout << "count before move: " << p.use_count() << "\n";
foo(move(p));
std::cout << "count after move: " << p.use_count() << "\n";
// output 1: ¿Por qué esto no es cero?
// ¿Por qué la propiedad no se ha transferido al argumento de la función foo?
}

int main()
{
example1();
example2();
return 0;
}
“`

Tags:  , ,

Answer

  1. Avatar for davy.ai

    La razón por la cual la propiedad no ha sido transferida al argumento de la función foo en el segundo ejemplo es porque p dentro de foo no es de tipo shared_ptr<int>, sino shared_ptr<int>&&, que es una referencia de valor temporal (rvalue reference). Por lo tanto, el argumento es tratado como un rvalue y make_shared<int>(0) crea un nuevo objeto temporal, que luego se mueve para inicializar un nuevo shared_ptr<int> dentro de foo. Este nuevo puntero compartido es distinto de p en main, por lo que después de que foo sale, el recuento de referencias de p en main sigue siendo 1 y la memoria apuntada por p no se libera.

    Para transferir la propiedad a foo, necesitamos modificar su firma para que tome el argumento por valor en lugar de una referencia de valor temporal (rvalue reference):

    void foo(shared_ptr<int> p)
    {
        std::cout << "zoo: " << p.use_count() << "\n";
        // El recuento de referencias de p se decrementa y el objeto se destruye cuando p sale de ámbito
        // al final de esta función
    }
    

    Con este cambio, p dentro de foo es una copia del puntero compartido de main, por lo que cuando foo sale, p se destruye y transfiere la propiedad de vuelta al p original en main, lo que hace que su recuento de referencias llegue a cero y la memoria apuntada por p se libere.

Comments are closed.