ultimo sintaxis programacion programa lenguaje evolucion estandar codigo c++ c++11 move-constructor

programacion - sintaxis de c++



¿Cuándo se llama Move Constructor? (2)

Estoy confundido acerca de cuándo se llama a un constructor de movimientos contra un constructor de copia. He leído las siguientes fuentes:

Mover constructor no es llamado en C ++ 0x

Mueva las referencias semánticas y de valores en C ++ 11

msdn

Todas estas fuentes son demasiado complicadas (solo quiero un ejemplo simple) o solo muestran cómo escribir un constructor de movimientos, pero no cómo llamarlo. He escrito un problema simple para ser más específico:

const class noConstruct{}NoConstruct; class a { private: int *Array; public: a(); a(noConstruct); a(const a&); a& operator=(const a&); a(a&&); a& operator=(a&&); ~a(); }; a::a() { Array=new int[5]{1,2,3,4,5}; } a::a(noConstruct Parameter) { Array=nullptr; } a::a(const a& Old): Array(Old.Array) { } a& a::operator=(const a&Old) { delete[] Array; Array=new int[5]; for (int i=0;i!=5;i++) { Array[i]=Old.Array[i]; } return *this; } a::a(a&&Old) { Array=Old.Array; Old.Array=nullptr; } a& a::operator=(a&&Old) { Array=Old.Array; Old.Array=nullptr; return *this; } a::~a() { delete[] Array; } int main() { a A(NoConstruct),B(NoConstruct),C; A=C; B=C; }

actualmente A, B y C tienen diferentes valores de puntero. Me gustaría que A tuviera un puntero nuevo, B que tuviera el puntero antiguo de C y C que tuviera un puntero nulo.

algo fuera de tema, pero si pudiera sugerir una documentación donde pudiera conocer en detalle estas nuevas características, le agradecería y probablemente no necesitaría hacer muchas más preguntas.


En primer lugar, su copia constructor está roto. Tanto los objetos copiados como los copiados a los mismos apuntarán a la misma Array e intentarán delete[] cuando salgan del alcance, lo que dará como resultado un comportamiento indefinido. Para arreglarlo, haga una copia de la matriz.

a::a(const a& Old): Array(new int[5]) { for( size_t i = 0; i < 5; ++i ) { Array[i] = Old.Array[i]; } }

Ahora, la asignación de movimientos no se realiza como usted quiere, ya que ambas declaraciones de asignación se asignan desde valores de l, en lugar de usar valores de r. Para que se realicen movimientos, debe moverse de un valor de r, o debe ser un contexto en el que un valor de l se pueda considerar como un valor de r (como la declaración de retorno de una función).

Para obtener el efecto deseado, use std::move para crear una referencia rvalue.

A=C; // A will now contain a copy of C B=std::move(C); // Calls the move assignment operator


Un constructor de movimiento se llama:

  • cuando un inicializador de objeto es std::move(something)
  • cuando un inicializador de objeto es std::forward<T>(something) y T no es un tipo de referencia lvalue (útil en la programación de plantillas para "reenvío perfecto")
  • cuando un inicializador de objetos es temporal y el compilador no elimina la copia / movimiento por completo
  • cuando se devuelve un objeto de clase de función local por valor y el compilador no elimina la copia / movimiento por completo
  • al lanzar un objeto de clase de función local y el compilador no elimina la copia / movimiento por completo

Esta no es una lista completa. Tenga en cuenta que un "inicializador de objeto" puede ser un argumento de función, si el parámetro tiene un tipo de clase (no de referencia).

a RetByValue() { a obj; return obj; // Might call move ctor, or no ctor. } void TakeByValue(a); int main() { a a1; a a2 = a1; // copy ctor a a3 = std::move(a1); // move ctor TakeByValue(std::move(a2)); // Might call move ctor, or no ctor. a a4 = RetByValue(); // Might call move ctor, or no ctor. a1 = RetByValue(); // Calls move assignment, a::operator=(a&&) }