C++ 声明一个 move/copy 操作会抑制相关操作的生成?
C++ declare a move/copy operation will suppress generation of related operations?
我在The C++ programming language中看到一句话,我很困惑:
• 如果程序员为 class 声明复制操作、移动操作或析构函数,则不会为该 [=51 生成复制操作、移动操作或析构函数=].
我写了一个测试代码如下所示:
#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;
}
结果是:
我定义了一个move assignment,应该没有书上说的默认生成copy assignment,但是a3怎么可能得到a1的copy?
另一个问题:
我修改了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;
}*/
结果是:
copy assignment怎么调用? a1+a2的结果是一个右值,这个右值怎么传给参数为const A&的copy赋值?请原谅我对右值的困惑
感谢任何帮助!
I define a move assignment, there should be not default copy assignment generated as said in the book
正确。
but how could a3 gets the copy of a1?
不符合标准。如果编译器没有给你诊断信息,那么编译器不符合标准。
The result of a1+a2
is a rvalue
正确。
how could this rvalue be passed to copy assignment whose argument is const A&
?
因为右值可以绑定到 const
的左值引用。临时对象的生命周期被延长以匹配引用的潜在生命周期。在引用参数的情况下,这是函数的持续时间。
根据 GCC 6 和那个(有点令人困惑的)句子的一些实际实验,这是我发现的:
- 如果您为 class 声明任何其他构造函数,则不会定义默认构造函数。
- 如果声明复制操作(构造函数或赋值运算符),则
其他复制操作是隐式生成的。然而,这一代已被 ISO 标准弃用,如书中句子后面的段落所述。
- 如果声明析构函数,则隐式生成复制操作。这也已弃用。
- 如果声明复制操作,移动操作将被隐式删除(默认为复制操作,如下所示)。
- 如果您声明了一个移动操作,另一个移动操作将被隐式删除。
- 如果您声明移动操作,则复制操作将被隐式删除。
- 如果声明析构函数,任何使用隐式移动操作的代码都会使用隐式复制操作(或显式复制操作,如果已定义)。但是,从上面了解到的内容,这可能会被隐式弃用。
- 如果未定义显式析构函数,则似乎总是为 class 生成默认(空)析构函数,无论是否定义了其他操作。
本声明具有前瞻性和简洁性。目前还没有完全实现C++ 11标准,但迟早会来。
C++11 标准第 12.8.7 节引用:
If the class definition does not explicitly declare a copy
constructor, one is declared implicitly. If the class definition
declares a move constructor or move assignment operator, the
implicitly declared copy constructor is defined as deleted; otherwise,
it is defined as defaulted (8.4). The latter case is deprecated if
the class has a user-declared copy assignment operator or a
user-declared destructor.
我在The C++ programming language中看到一句话,我很困惑:
• 如果程序员为 class 声明复制操作、移动操作或析构函数,则不会为该 [=51 生成复制操作、移动操作或析构函数=].
我写了一个测试代码如下所示:
#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;
}
结果是:
我定义了一个move assignment,应该没有书上说的默认生成copy assignment,但是a3怎么可能得到a1的copy?
另一个问题:
我修改了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;
}*/
结果是:
copy assignment怎么调用? a1+a2的结果是一个右值,这个右值怎么传给参数为const A&的copy赋值?请原谅我对右值的困惑
感谢任何帮助!
I define a move assignment, there should be not default copy assignment generated as said in the book
正确。
but how could a3 gets the copy of a1?
不符合标准。如果编译器没有给你诊断信息,那么编译器不符合标准。
The result of
a1+a2
is a rvalue
正确。
how could this rvalue be passed to copy assignment whose argument is
const A&
?
因为右值可以绑定到 const
的左值引用。临时对象的生命周期被延长以匹配引用的潜在生命周期。在引用参数的情况下,这是函数的持续时间。
根据 GCC 6 和那个(有点令人困惑的)句子的一些实际实验,这是我发现的:
- 如果您为 class 声明任何其他构造函数,则不会定义默认构造函数。
- 如果声明复制操作(构造函数或赋值运算符),则 其他复制操作是隐式生成的。然而,这一代已被 ISO 标准弃用,如书中句子后面的段落所述。
- 如果声明析构函数,则隐式生成复制操作。这也已弃用。
- 如果声明复制操作,移动操作将被隐式删除(默认为复制操作,如下所示)。
- 如果您声明了一个移动操作,另一个移动操作将被隐式删除。
- 如果您声明移动操作,则复制操作将被隐式删除。
- 如果声明析构函数,任何使用隐式移动操作的代码都会使用隐式复制操作(或显式复制操作,如果已定义)。但是,从上面了解到的内容,这可能会被隐式弃用。
- 如果未定义显式析构函数,则似乎总是为 class 生成默认(空)析构函数,无论是否定义了其他操作。
本声明具有前瞻性和简洁性。目前还没有完全实现C++ 11标准,但迟早会来。
C++11 标准第 12.8.7 节引用:
If the class definition does not explicitly declare a copy constructor, one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy constructor is defined as deleted; otherwise, it is defined as defaulted (8.4). The latter case is deprecated if the class has a user-declared copy assignment operator or a user-declared destructor.