Я запутался, когда конструктор перемещения вызывается против конструктора копирования.
Я прочитал следующие источники:
Конструктор Move не вызывается в C ++ 0x
Переместить семантику и rvalue ссылки в C ++ 11
Все эти источники либо слишком сложны (я просто хочу простой пример), либо показывают только, как написать конструктор перемещения, но не как его вызвать. Я написал простую задачу, чтобы быть более конкретным:
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 имел нулевой указатель.
немного не по теме, но если бы кто-то мог предложить документацию, где я мог бы подробно узнать об этих новых функциях, я был бы благодарен и, вероятно, не должен был бы задавать еще много вопросов.
Конструктор перемещения называется:
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&&)
}
Прежде всего, ваш конструктор копирования не работает. Копируемые и копируемые объекты указывают на одно и то же. 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