在我正在阅读的书中(C++ Without Fear),它表示如果你没有为一个类声明一个默认构造函数,那么编译器会为你提供一个"零逻辑".我已经尝试过这个,而且我没有看到任何归零行为.我也找不到任何在Google上提到这一点的内容.这只是一个错误或特定编译器的怪癖?
Mar*_*ork 63
如果未定义构造函数,编译器将为您定义默认构造函数.
这个的实现
注意:
POD数据(int,float,pointer等)没有显式构造函数,但默认操作是什么都不做(在C++哲学的风向标中;除非我们明确要求,否则我们不想支付任何费用它).
如果没有定义析构函数/复制构造函数/赋值运算符,则编译器会为您构建其中一个(因此类总是有一个析构函数/复制构造函数/赋值运算符(除非您作弊并明确声明一个但不定义它)).
默认实现是:
注意POD数据的复制构造/分配操作符只是复制数据(因此与RAW指针相关的浅复制问题).
Bil*_*ard 38
我认为值得指出的是,如果你不提供任何构造函数,那么默认构造函数将只由编译器创建.这意味着如果您只提供一个带参数的构造函数,编译器将不会为您创建默认的no-arg构造函数.
您的书中讨论的归零行为可能特定于特定编译器.我一直认为它可以变化,你应该明确初始化任何数据成员.
nob*_*bar 36
- 编译器是否自动生成默认构造函数?
- 隐式生成的默认构造函数是否执行零初始化?
如果您在法律上解析2003标准的语言,那么答案是肯定的,不是.但是,这不是全部故事,因为与用户定义的默认构造函数不同,从头开始创建对象时并不总是使用隐式定义的默认构造函数 - 还有另外两种情况:无构造和成员值初始化.
"无结构"的情况实际上只是一种技术性,因为它在功能上与调用普通的默认构造函数没有什么不同.另一种情况是更加有趣:成员明智值初始化通过使用调用"()" [仿佛明确调用一个没有参数的构造函数]和它绕过什么技术上称为的默认构造函数.相反,它递归地对每个数据成员执行值初始化,对于原始数据类型,这最终解析为零初始化.
实际上,编译器提供了两个不同的隐式定义的默认构造函数.其中一个确实执行原始成员数据的零初始化,而另一个不执行.以下是一些如何调用每种类型的构造函数的示例:
MyClass a; // default-construction or no construction
MyClass b = MyClass(); // member-wise value-initialization
Run Code Online (Sandbox Code Playgroud)
和
new MyClass; // default-construction or no construction
new MyClass(); // member-wise value-initialization
Run Code Online (Sandbox Code Playgroud)
注意:如果用户声明的默认构造函数确实存在,那么成员方式的值初始化只是调用它并停止.
这里有一个关于标准说明的详细细节......
如果不声明构造函数,编译器会隐式创建默认构造函数[12.1-5]
默认构造函数不初始化基元类型[12.1-7]
MyClass() {} // implicitly defined constructor
Run Code Online (Sandbox Code Playgroud)如果使用"()"初始化对象,则不会直接调用默认构造函数.相反,它引发了一系列称为值初始化的规则[8.5-7]
值初始化的净效果是永远不会调用隐式声明的默认构造函数.相反,调用一个递归的成员值初始化,它最终将零初始化任何原始成员,并在任何具有用户声明的构造函数的成员上调用默认构造函数[8.5-5]
值初始化甚至适用于原始类型 - 它们将被零初始化.[8.5-5]
a = int(); // equivalent to int a=0;
Run Code Online (Sandbox Code Playgroud)所有这些对于大多数目的来说都没有实际意义.类的编写者通常不能假设数据成员在隐式初始化序列期间将被清零 - 因此,如果任何自我管理类具有需要初始化的任何原始数据成员,则应该定义自己的构造函数.
那么这什么时候重要?
在某些情况下,通用代码可能会强制初始化未知类型.值初始化提供了一种方法.请记住,如果用户提供了构造函数,则不会发生隐式零初始化.
默认情况下,std :: vector包含的数据是值初始化的.这可以防止内存调试器识别与否则未初始化的内存缓冲区相关的逻辑错误.
vector::resize( size_type sz, T c=T() ); // default c is "value-initialized"
Run Code Online (Sandbox Code Playgroud)可以使用值初始化语法对整个基元类型或"普通旧数据"(POD)类型结构进行零初始化.
new int[100]();
Run Code Online (Sandbox Code Playgroud)这篇文章提供了有关标准版本之间差异的更多细节,并且还指出了标准在主要编译器中的应用不同的情况.
Ecl*_*pse 11
为类创建的默认构造函数不会初始化内置类型,但它将在所有用户定义的成员上调用默认构造函数:
class Foo
{
public:
int x;
Foo() : x(1) {}
};
class Bar
{
public:
int y;
Foo f;
Foo *fp;
};
int main()
{
Bar b1;
ASSERT(b1.f.x == 1);
// We know nothing about what b1.y is set to, or what b1.fp is set to.
// The class members' initialization parallels normal stack initialization.
int y;
Foo f;
Foo *fp;
ASSERT(f.x == 1);
// We know nothing about what y is set to, or what fp is set to.
}
Run Code Online (Sandbox Code Playgroud)
如果用户创建的构造函数和析构函数不存在,编译器将生成默认构造函数和析构函数.这些不会修改任何数据成员的状态.
在C++(和C)中,不保证任何已分配数据的内容.在调试配置中,某些平台会将此值设置为已知值(例如0xFEFEFEFE)以帮助识别错误,但不应依赖此错误.
清零仅发生在全局变量中。因此,如果您的对象是在全局范围内声明的,则其成员将被清零:
class Blah
{
public:
int x;
int y;
};
Blah global;
int main(int argc, char **argv) {
Blah local;
cout<<global.x<<endl; // will be 0
cout<<local.x<<endl; // will be random
}
Run Code Online (Sandbox Code Playgroud)