Когда вызывается Move Constructor?

Я запутался, когда конструктор перемещения вызывается против конструктора копирования.
Я прочитал следующие источники:

Конструктор Move не вызывается в C ++ 0x

Переместить семантику и rvalue ссылки в C ++ 11

MSDN

Все эти источники либо слишком сложны (я просто хочу простой пример), либо показывают только, как написать конструктор перемещения, но не как его вызвать. Я написал простую задачу, чтобы быть более конкретным:

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;
}

в настоящее время A, B и C имеют разные значения указателя. Я хотел бы, чтобы A имел новый указатель, B имел старый указатель C, а C имел нулевой указатель.

немного не по теме, но если бы кто-то мог предложить документацию, где я мог бы подробно узнать об этих новых функциях, я был бы благодарен и, вероятно, не должен был бы задавать еще много вопросов.

20

Решение

Конструктор перемещения называется:

  • когда инициализатор объекта std::move(something)
  • когда инициализатор объекта std::forward<T>(something) а также T не является ссылочным типом lvalue (полезно в шаблонном программировании для «идеальной пересылки»)
  • когда инициализатор объекта является временным и компилятор не устраняет полностью копирование / перемещение
  • при возврате объекта класса локальной функции по значению, а компилятор не устраняет полностью копирование / перемещение
  • когда выбрасывает объект класса локальной функции и компилятор не устраняет полностью копирование / перемещение

Это не полный список. Обратите внимание, что «инициализатор объекта» может быть аргументом функции, если параметр имеет тип класса (не ссылочный).

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&&)
}
26

Другие решения

Прежде всего, ваш конструктор копирования не работает. Копируемые и копируемые объекты указывают на одно и то же. Array и оба будут пытаться delete[] это когда они выходят за рамки, что приводит к неопределенному поведению. Чтобы это исправить, сделайте копию массива.

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

Теперь, перемещение не выполняется так, как вы хотите, потому что оба оператора присваивания присваиваются из lvalues ​​вместо использования rvalues. Для выполнения перемещений вы должны двигаться от значения r, или это должен быть контекст, в котором значение l можно считать значением (например, оператор возврата функции).

Для получения желаемого эффекта используйте std::move создать ссылку на значение.

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

По вопросам рекламы [email protected]