C++中的复制构造函数和赋值运算符
copy constructor and assignment operator in C++
class MyClass
{
private:
int x;
public:
MyClass(int x)
{
this->x = x;
}
MyClass(const MyClass& other)
{
this->x = other.x;
}
};
int main()
{
MyClass first(1);
MyClass second = first; //(1)
first = second; // (2)
MyClass third = MyClass(2); // (3)
}
为什么第一行 MyClass second = first
调用复制构造函数而第二行 first = second;
调用赋值运算符,为什么第三行 MyClass third = MyClass(2);
不像第一行那样调用复制构造函数。
最后,第 3 行到底做了什么 MyClass third = MyClass(2);
.
构造函数,包括拷贝构造函数,用于初始化一个class对象。赋值运算符用于修改已经初始化的对象。
第 (1) 行调用复制构造函数,因为它正在初始化对象 second
。赋值运算符与 =
符号也用于此语法这一事实无关。第 (2) 行赋值给已经存在的 first
,因此使用赋值运算符。
在C++14及更早的第(3)行,允许编译器为MyClass(2)
表达式创建一个临时对象,然后使用复制构造函数初始化third
,然后摧毁暂时的。但是也允许编译器“elide”(去掉)临时对象、拷贝构造函数和临时析构函数,只是像原来的临时对象一样直接初始化third
。这种复制省略是 C++ 允许优化的一种情况,这可能会导致可观察到的行为发生差异,因为复制构造函数 and/or 析构函数可能具有优化跳过的副作用(如打印痕迹)。
在 C++17 及之后的第 (3) 行中,我们说表达式 MyClass(2)
具有结果对象 third
。所以表达式指定 third
是用参数 2
直接初始化的。不涉及复制构造函数或临时对象。 C++17 的此功能通常称为“强制复制省略”,因为其行为与编译器能够应用复制省略优化的 C++14 程序相同。但从技术上讲,这不是复制省略,因为不涉及要省略的副本。还有一些其他情况下,复制省略对于编译器来说是可选的。
class MyClass
{
private:
int x;
public:
MyClass(int x)
{
this->x = x;
}
MyClass(const MyClass& other)
{
this->x = other.x;
}
};
int main()
{
MyClass first(1);
MyClass second = first; //(1)
first = second; // (2)
MyClass third = MyClass(2); // (3)
}
为什么第一行 MyClass second = first
调用复制构造函数而第二行 first = second;
调用赋值运算符,为什么第三行 MyClass third = MyClass(2);
不像第一行那样调用复制构造函数。
最后,第 3 行到底做了什么 MyClass third = MyClass(2);
.
构造函数,包括拷贝构造函数,用于初始化一个class对象。赋值运算符用于修改已经初始化的对象。
第 (1) 行调用复制构造函数,因为它正在初始化对象 second
。赋值运算符与 =
符号也用于此语法这一事实无关。第 (2) 行赋值给已经存在的 first
,因此使用赋值运算符。
在C++14及更早的第(3)行,允许编译器为MyClass(2)
表达式创建一个临时对象,然后使用复制构造函数初始化third
,然后摧毁暂时的。但是也允许编译器“elide”(去掉)临时对象、拷贝构造函数和临时析构函数,只是像原来的临时对象一样直接初始化third
。这种复制省略是 C++ 允许优化的一种情况,这可能会导致可观察到的行为发生差异,因为复制构造函数 and/or 析构函数可能具有优化跳过的副作用(如打印痕迹)。
在 C++17 及之后的第 (3) 行中,我们说表达式 MyClass(2)
具有结果对象 third
。所以表达式指定 third
是用参数 2
直接初始化的。不涉及复制构造函数或临时对象。 C++17 的此功能通常称为“强制复制省略”,因为其行为与编译器能够应用复制省略优化的 C++14 程序相同。但从技术上讲,这不是复制省略,因为不涉及要省略的副本。还有一些其他情况下,复制省略对于编译器来说是可选的。