C++ объявить операцию перемещения / копирования будет подавлять генерацию связанных операций?
Я видел предложение на языке программирования C++, с которым я запутался:
• Если программист объявляет операцию копирования, операцию перемещения или деструктор для класса, для этого класса не создается операция копирования, операция перемещения или деструктор.
Я написал тестовый код, показанный ниже:
#include <iostream>
using namespace std;
class A
{
public:
A() :a(0){}
A(int _a) :a(_a){}
int get() const
{
return a;
}
/*A& operator=(const A &x)
{
a = x.a;
cout << "A copy assignment" << endl;
return *this;
}*/
A& operator=(A&&x)
{
cout << "A move assignment" << endl;
swap(a, x.a);
return *this;
}
private:
int a;
};
A operator+(const A &x, const A &y)
{
A temp{ x.get() + y.get() };
return temp;
}
int main()
{
A a1(1), a2(2), a3;
a3 = a1;
cout << a3.get() << endl;
return 0;
}
Я определяю назначение перемещения, не должно быть назначений копирования по умолчанию, сгенерированных, как сказано в книге, но как a3 может получить копию a1?
Другой вопрос:
Я изменил выражение присваивания a3:
a3 = a1+a2;
Затем я закомментирую назначение перемещения и удаляю комментарий о назначении копирования:
A& operator=(const A &x)
{
a = x.a;
cout << "A copy assignment" << endl;
return *this;
}
/*
A& operator=(A&&x)
{
cout << "A move assignment" << endl;
swap(a, x.a);
return *this;
}*/
как может быть вызвано назначение копирования? Результатом a1+a2 является rvalue, как это значение может быть передано для копирования присваивания, аргументом которого является const A &? Прости мое замешательство в отношении ценности
любая помощь приветствуется!
3 ответа
Я определяю назначение перемещения, должно быть не назначенное по умолчанию назначение копии, сгенерированное как сказано в книге
Правильный.
но как мог а3 получить копию а1?
Это не могло в соответствии со стандартом. Если компилятор не дает вам диагностическое сообщение для этого, то компилятор не соответствует стандарту.
Результат
a1+a2
это значение
Правильный.
как можно передать это значение для копирования присваивания, аргумент которого
const A&
?
Потому что rvalues может быть привязан к lvalue ссылкам на const
, Время жизни временного объекта увеличивается, чтобы соответствовать потенциальному времени жизни ссылки. Это для продолжительности функции в случае ссылочного аргумента.
Это заявление является дальновидным и кратким. Он еще не полностью реализовал стандарт C++11, но рано или поздно он появится.
Стандартный раздел С++11 12.8.7 цитирует:
Если определение класса явно не объявляет конструктор копирования, он объявляется неявно. Если определение класса объявляет конструктор перемещения или оператор присваивания перемещения, неявно объявленный конструктор копирования определяется как удаленный; в противном случае он определяется как дефолтный (8.4). Последний случай считается устаревшим , если в классе есть объявленный пользователем оператор присваивания копии или объявленный пользователем деструктор.
Основываясь на некоторых практических экспериментах с GCC 6 и на этом (несколько запутанном) предложении, я нашел следующее:
- Если вы объявляете любой другой конструктор для класса, конструктор по умолчанию не определен.
- Если вы объявляете операцию копирования (конструктор или оператор присваивания), другая операция копирования генерируется неявно. Однако это поколение не рекомендуется стандартом ISO, как описано в параграфе, следующем за предложением в книге.
- Если вы объявляете деструктор, операции копирования генерируются неявно. Это также не рекомендуется.
- Если вы объявляете операцию копирования, операции перемещения неявно удаляются (по умолчанию копируются операции, как показано ниже).
- Если вы объявляете операцию перемещения, другая операция перемещения неявно удаляется.
- Если вы объявляете операцию перемещения, операции копирования неявно удаляются.
- Если вы объявляете деструктор, любой код, который использует неявные операции перемещения, вместо этого использует неявные операции копирования (или явные, если они определены). Тем не менее, это может быть неявно осуждается из того, что изучено выше.
- Если явный деструктор не был определен, деструктор по умолчанию (пустой), кажется, всегда генерируется для класса, независимо от того, какие другие операции были или не были определены.