Soy nuevo en SO, así que avíseme si necesito cambiar algo. Hice todo lo posible para ser tan minucioso y proporcionar un código de ejemplo. Sé que se han hecho muchas preguntas similares, aunque no he podido encontrar una que coincida con mi problema específico.

Además, soy consciente de que lo que estoy haciendo no es algo que uno haría en código 'real', solo estoy tratando de comprender mejor los valores r / l / p / x ...

Tengo una base y una clase derivada, ambas tienen los constructores predeterminados, copiar y mover. Ahora quiero tener el constructor de copia de la clase derivada que llama al constructor de movimiento de la clase base.

class Base
{
public:
    Base(){ std::cout << "default base constructor called.\n"; }

    Base(Base const &other) { std::cout << "copy base constructor called.\n"; }

    Base(Base &&tmp) { std::cout << "move base constructor called.\n"; }
};

Y básicamente la misma para la clase derivada:

class Derived : public Base
{
public:
    Derived(){ std::cout << "default derived constructor called.\n";}

    Derived(Derived const &other)
    :
        Base(std::move(other))   // here I want to call Base(Base &&tmp)
    {
        std::cout << "copy derived constructor called.\n";
    }

    Derived(Derived &&tmp)
    :
        Base(std::move(tmp))     // correctly calls Base(Base &&tmp)!
    {
        std::cout << "move derived constructor called.\n";
    }
};

Entonces, en mi función principal, ahora quiero llamar al constructor de copia, que luego llama al constructor de movimiento de la clase base.

int main()
{
    Derived der{};
    Derived der_copy{ der };
    Derived der_move{ std::move(der) };
}

El resultado que obtendría es este:

default base constructor called.
default derived constructor called.
copy base constructor called.         <-- why not move?
copy derived constructor called.
move base constructor called.
move derived constructor called.

Estaba esperando lo siguiente:

default base constructor called.
default derived constructor called.
move base constructor called.
copy derived constructor called.
move base constructor called.
move derived constructor called.

Entonces, cuando uso std::move(tmp) en el constructor de movimiento derivado (así sucesivamente Base &&tmp) se llama al constructor de movimiento base, pero cuando uso std::move(other) en el constructor de copia derivada (así sucesivamente {{ X3}}) que se llama el constructor de copia base?

Tbh, esto parece tan extraño que me temo que cometí un error en mi código, verifiqué todo varias veces, pero parece que no puedo obtener el constructor de base de movimiento llamado en el caso anterior ...

¡Gracias por tu ayuda!

0
picklepick 8 dic. 2019 a las 17:06

2 respuestas

La mejor respuesta

En el constructor de copia

Derived(const Derived& other)

std::move(other) dará como resultado una expresión xvalue del tipo const Derived&&.

Este es un tipo legal pero algo extraño: std::move(other) es un objeto temporal, pero no puede moverse de él, porque es constante. Dichas referencias tienen un número limitado de casos de uso. Consulte las declaraciones de std::as_const y std::ref para un ejemplo en particular.

const Derived&& no se puede unir a Base&&, es por eso que durante la resolución de sobrecarga entre

Base(const Base&)
Base(Base&&)

La primera es elegida por el compilador.

A riesgo de tener un comportamiento indefinido, puede desechar la constidad y escribir

Derived(const Derived& other) : Base(std::move(const_cast<Derived&>(other))) {}

Para llamar al constructor de movimiento de Base. Pero no lo hagas en código real.

2
Evg 8 dic. 2019 a las 15:12

Necesita cambiar su clase Base de esta manera:

Base(const Base &&tmp) { std::cout << "move base constructor called.\n"; }

1
boyanhristov96 8 dic. 2019 a las 14:25