简单问题:以下陈述是否相同?或者是第二个在幕后做更隐含的事情(如果是,那又怎样?)
myClass x(3);
myClass x = myClass(3);
谢谢!
答案 0 :(得分:25)
它们并不完全相同。第一种称为“直接初始化”,而第二种称为“复制初始化”。
现在,标准制定了两条规则。第一种是直接初始化和复制初始化,其中初始化器是初始化对象的类型。第二个规则是在其他情况下进行复制初始化。
因此,从这个角度来看,两者都被称为一个 - 第一个 - 规则。如果您具有相同类型的复制初始化,则允许编译器删除副本,因此它可以构造您直接创建到初始化对象中的临时文件。因此,您可以使用生成的相同代码完成最终结果。但是复制构造函数,即使复制被省略(优化出来),仍然必须可用。即如果你有一个私有拷贝构造函数,如果它出现的代码无法访问它,那么该代码是无效的。
第二种称为复制初始化,因为如果初始化程序的类型是不同的类型,则在尝试将右侧隐式转换为左侧时会创建一个临时对象:
myclass c = 3;
当存在一个带有int的构造函数时,编译器会创建一个myclass类型的临时对象。然后用它临时初始化对象。同样在这种情况下,可以直接在初始化对象中创建临时创建。您可以通过在类的构造函数/析构函数中打印消息并使用GCC选项-fno-elide-constructors
来执行这些步骤。它不会试图删除副本。
另外,上面的代码与赋值运算符无关。在这两种情况下,会发生什么是初始化。
答案 1 :(得分:8)
如果编译器未实现复制省略,则第二个可能会或可能不会要求额外的myclass
对象构造。但是,大多数构造函数都默认启用了复制省略,即使没有任何优化开关也是如此。
注意初始化,而构造永远不会调用赋值运算符。
始终,请记住:
赋值:已存在的对象获取新值
初始化:新对象在其诞生时获取值。
答案 2 :(得分:5)
在第二个中,首先创建一个临时对象,然后使用myClass的复制构造函数将其复制到对象x中。因此两者都不一样。
答案 3 :(得分:4)
我写下以下内容尝试并说明了解发生了什么:
#include <iostream>
using namespace std;
class myClass
{
public:
myClass(int x)
{
this -> x = x;
cout << "int constructor called with value x = " << x << endl;
}
myClass(const myClass& mc)
{
cout << "copy constructor called with value = " << mc.x << endl;
x = mc.x;
}
myClass & operator = (const myClass & that)
{
cout << "assignment called" << endl;
if(this != &that)
{
x = that.x;
}
return *this;
}
private:
int x;
};
int main()
{
myClass x(3);
myClass y = myClass(3);
}
当我编译并运行此代码时,我得到以下输出:
$ ./a.out
int constructor called with value x = 3
int constructor called with value x = 3
这将似乎表示在main函数中进行的两次调用之间没有区别,但这是错误的。正如litb指出的那样,复制构造函数必须才能使此代码正常工作,即使在这种情况下它被忽略了。为了证明这一点,只需将上面代码中的复制构造函数移动到类定义的私有部分即可。您应该看到以下错误:
$ g++ myClass.cpp
myClass.cpp: In function ‘int main()’:
myClass.cpp:27: error: ‘myClass::myClass(const myClass&)’ is private
myClass.cpp:37: error: within this context
另请注意,赋值运算符从不调用。