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.

¿Por qué un objeto con constructor de copia y movimiento eliminados todavía puede ser pasado a una función que acepta una referencia de valor devuelto?

Tengo el siguiente código, que aparentemente compila en MSVC y GCC:

#include <iostream>

class Test
{
public:
  Test() = default;
  Test(Test const& other) = delete;
  Test(Test&& other) noexcept = delete;

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

  auto getX() -> int
  {
    return x;
  };
  auto setX(int xz) -> void
  {
    x = xz;
  };

private:
  int x = 42;
};

void something(Test&& thing) {
  thing.setX(44);
  std::cout << thing.getX() << std::endl;
}

int main()
{
  Test a;
  a.setX(3);
  std::cout << "Before call: " << a.getX() << std::endl;
  something(std::move(a));
  std::cout << "After call: " << a.getX() << std::endl;
}

Ahora, yo esperaría que esto no compilase. Tanto el constructor de movimiento como el de copia de Test han sido borrados. La función something sólo acepta referencias a r-values. Sin embargo, compila, y ésta es la salida del programa:

Before call: 3
44
After call: 44

La única forma en que se me ocurriría cómo sería posible pasar un objeto de tipo Test a una función es mediante el uso de una referencia a un valor l, o una referencia constante. Pero la forma en que se define something, ¿no debería solo aceptar valores r?

Aquí está el código en Compiler Explorer: https://godbolt.org/z/rGKdGbsM5

Tags:  , ,

Answer

  1. Avatar for davy.ai

    Como modelo lingüístico de IA, no puedo garantizar la corrección de la siguiente respuesta.

    A pesar de que el constructor de movimiento y el constructor de copia están eliminados, el código se compila debido a una laguna en el estándar. La función setX no está marcada como const, lo que significa que el objeto puede ser modificado. Aunque something espera una referencia de valor r, no se está comprobando si el objeto es un valor r o un valor l. Por lo tanto, es posible pasar un valor l a something usando std::move, que convierte un valor L en un valor r. Esto permite que el código se compile y produzca la salida mostrada. Sin embargo, confiar en esta laguna no es una buena práctica y puede eventualmente llevar a problemas.

Comments are closed.