我正在使用Visual Studio 2013.
我有以下代码
class Foo{
public:
Foo(){};
Foo* fPtr;
float f;
};
int main()
{
Foo foo1; // No Warning. fPtr is initialized to NULL, f is set to 0.0.
Foo foo2(foo1); // Compiles fine. Uses compiler generated copy constructor
return 0;
}
现在考虑相同的代码,但没有用户定义的默认构造函数。
class Foo{
public:
// No user defined default constructor, or equivalently
// Foo() = default;
Foo* fPtr;
float f;
};
int main()
{
Foo foo1; // Neither fPtr nor f are initialized, both contain garbage.
//Foo foo2(foo1); // error C4700: uninitialized local variable 'foo1' used
return 0;
}
我认为用户定义的默认构造函数和隐式定义的默认构造函数是等价的,但在我看来它们不是。
编译器如何定义默认构造函数?
在这种情况下,我对使用编译器定义的默认构造函数持谨慎态度,并且总是提供我自己的,即使有时是空的默认构造函数。我误解了什么吗?
答案 0 :(得分:5)
在实现时,implicitly-defined default constructor 与用户定义的构造函数相同,具有空主体和空初始化列表。
如果隐式声明的默认构造函数未定义为已删除,则编译器会定义(即,函数体生成并编译),如果使用了odr,它与用户具有完全相同的效果 - 使用空主体和空初始化列表定义构造函数。
和
Foo foo1; // No Warning. fPtr is initialized to NULL, f is set to 0.0.
没有。不仅对于第二个代码示例,即使对于第一个代码示例,foo1.fPtr
和foo1.f
也未初始化;空的用户定义构造函数根本不初始化任何成员。
关于编译器警告,似乎MSVS认为如果提供并调用了用户定义的构造函数,则可以认为该对象已经初始化。但是你需要确保构造函数执行或不执行预期的操作。
请注意,它们仍有一些微妙的不同副作用;例如list initialization和value intialization,(此处不使用default initialization)。例如对
Foo foo1{};
然后对于第一种情况,将调用用户定义的默认构造函数;因为它没有做任何事情foo1.fPtr
和foo1.f
仍未被初始化;但对于第二种情况,将执行aggregate initialization(因为缺少用户定义的构造函数),然后将foo1.fPtr
和foo1.f
进行值初始化。即foo1.fPtr
初始化为nullptr
,foo1.f
初始化为0
。