我不明白以下两个陈述之间的区别:
Thing thing;
Thing thing = Thing();
两者都创建一个Thing
对象并将其放在变量thing
中,对吗?如果是这样,有两个问题:
1-两者之间有哪些技术差异?
2-我应该何时使用另一个?
请注意:
A-我没有使用C ++ 11。
B- C ++新手,请使用新手友好的词语。
答案 0 :(得分:4)
Thing thing;
是默认初始化。如果Thing
是类类型,它会调用Thing
的默认构造函数,就是这样。
Thing thing = Thing();
value-initializes临时Thing
,然后将该临时副本复制/移动到thing
。在实践中,编译器将忽略复制/移动,使其有效地进行值初始化,但这仍然需要复制/移动构造函数可用。获取值初始化语义需要= Thing();
语法,因为Thing thing();
是一个令人烦恼的解析。 *
值初始化和默认初始化之间的区别在于,在某些情况下(确切的情况depend on the version of the standard,但是没有用户提供的构造函数的非联合类类型,以及非类非数组类型,以及这些类型的数组在所有版本中都有资格),值初始化将在调用默认构造函数之前首先进行零初始化。
如果Thing
可以是非类(例如,在模板中)或者是将获得零初始化处理的类类型(例如,POD类)并且您是使用第二个版本是有帮助的希望它有明确的价值观。
* Thing thing{};
在初始化语义上与C ++ 14中的普通值初始化略有不同。 子>
答案 1 :(得分:3)
符号
Thing thing = Thing();
执行复制初始化的可以在C ++ 03模板代码中用于有效地默认构造Thing
。问题是,这也适用于内置类型Thing
,例如int
。这种扭曲的表示法因为写Thing thing();
只是声明一个函数(一个特别的“最令人烦恼的解析”)。
在C ++ 11中,可以改为编写
Thing thing{};
C ++ 03中的另一种技术是将Thing
包裹在struct
中,如下所示:
struct Initialized_thing
{
Thing thing;
Initialized_thing(): thing() {}
};
答案 2 :(得分:0)
不同之处在于,如果无法访问复制或移动构造函数,编译器可能会为第二个定义发出错误。例如,它们可能被定义为私有或已删除。
Thing thing;
Thing thing = Thing(); // there may be a compiler error
例如,考虑以下程序
int main()
{
class A
{
private:
A( const A & );
public:
A() {}
};
A a;
return 0;
}
上面的程序将成功编译,而下面的程序将不会被编译(如果只有编译器不是例如MS VC ++ 2010)
int main()
{
class A
{
private:
A( const A & );
public:
A() {}
};
A a = A();
return 0;
}
本声明中的另一个区别
A a;
a是默认初始化
在本声明中
A a = A();
a初始化值。
来自C ++标准
2表达式T(),其中T是简单类型说明符或 非数组完整对象类型的typename-specifier或 (可能是cv-qualified)void类型,创建指定的prvalue type,其值是由value-initializing(8.5)生成的 T型物体;没有为void()情况进行初始化。
考虑另一个例子
int main()
{
class A
{
int x;
};
A a1;
A a2 = A();
return 0;
}
对于x的a1值将是未指定的,而对于s2的x值将等于0.
答案 3 :(得分:0)
正如其他人编写的语法
Thing obj;
将default-initialize您的对象,而语法
Thing obj = Thing();
将value-initialize您的对象。
第二种语法会导致涉及更多内容:
它们通常用于不同的目的,虽然第一个是最常用于初始化对象的,但后者在值初始化含义上是不同的。
我建议阅读文档以了解值和默认初始化之间的差异,无论如何,显示差异的简单示例如下:
class Thing {
public:
int data;
Thing() {
cout << "default ctor" << endl;
}
Thing(const Thing&) {
cout << "copy ctor" << endl;
}
const Thing& operator=(const Thing&) {
cout << "operator=" << endl;
return *this;
}
};
struct Thingy {
int data;
};
int main() {
cout << is_pod<Thing>::value << endl; // Thing is NOT pod
Thing thing; // Calls default constructor
cout << thing.data << endl; // Garbage
Thing thing2 = Thing(); // Copy elision is able to optimize this (standard-defined 12.8/31). Anyway a copy/move constructor must be accessible
cout << thing2.data << endl; // Garbage
// -----------------------------------------------------
cout << is_pod<Thingy>::value << endl; // Thingy IS pod
Thingy thingy1;
cout << thingy1.data << endl; // garbage
Thingy thingy2 = Thingy();
cout << thingy2.data << endl; // zero-initialized!
}
上面的代码将打印
0 // Not a POD
default ctor
-1326900592 // garbage
default ctor
-1326900592 // garbage
// ---------------------------
1 // POD
-1326900592 // garbage
0 // zero-initialized