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.

Llamada inesperada al constructor por defecto al usar la semántica de movimiento.

Tengo dos piezas de código similares. La primera versión llama inesperadamente al constructor predeterminado mientras que la segunda no lo hace. Ambas llaman al operador de movimiento / constructor de movimiento, respectivamente, como se esperaba.

class MyResource
{
public:
    MyResource() : m_data(0) { std::cout << "Constructor Predeterminado" << std::endl; }
    MyResource(int data) : m_data(data) { std::cout << "Constructor con Entero" << std::endl; }

    MyResource(MyResource const& other) = delete;
    MyResource& operator=(MyResource const& other) = delete;

    MyResource(MyResource&& other) noexcept : m_data(other.m_data) { std::cout << "Constructor de Movimiento" << std::endl; }
    MyResource& operator=(MyResource&& other) noexcept { std::cout << "Operador de Movimiento" << std::endl; m_data = other.m_data; return *this; }

    ~MyResource() { std::cout << "Destructor" << std::endl; }

private:
    int m_data = 0;
};

class MyWrapper
{
public:
    MyWrapper(MyResource&& resource)
        // : m_resource(std::move(resource)) // Versión 2
    {
        // m_resource = std::move(resource); // Versión 1
    }

private:
    MyResource m_resource;
};

Mi uso de prueba es:

MyWrapper* wrapper = new MyWrapper(MyResource(1));
delete wrapper;

Con la Versión 1, obtengo:

> Constructor con Entero
> Constructor Predeterminado
> Operador de Movimiento
> Destructor
> Destructor

Mientras que la Versión 2 muestra:

> Constructor con Entero
> Constructor de Movimiento
> Destructor
> Destructor

¿Cuál es la razón detrás de esta diferencia?
¿Por qué la Versión 1 llama al constructor predeterminado?

Tags:  ,

Answer

  1. Avatar for davy.ai

    La razón de esta diferencia es que en la Versión 1, la variable miembro m_resource se inicializa por defecto antes de llamar al operador de movimiento. Esto se debe a que el cuerpo del constructor ya se está ejecutando en el momento en que se llama al operador de movimiento, y la inicialización por defecto ocurre antes de cualquier inicialización explícita en el cuerpo del constructor.

    En la Versión 2, la variable miembro m_resource se inicializa directamente mediante los parámetros del constructor de movimiento, por lo que no se necesita una inicialización por defecto.

    Para evitar la inicialización por defecto en la Versión 1, puedes usar la sintaxis de la lista de inicialización de miembros para inicializar directamente m_resource con std::move(resource), como en la Versión 2.

Comments are closed.