在我目前正在阅读的书(C++ Without Fear)中提到,如果你没有为一个类声明默认的构造函数,编译器会替你提供一个,并且“将每个数据成员清零”。我进行了测试,但我没有看到任何清零行为。我也没能在Google上找到任何相关信息。这是一个错误还是特定编译器的怪癖呢?
在我目前正在阅读的书(C++ Without Fear)中提到,如果你没有为一个类声明默认的构造函数,编译器会替你提供一个,并且“将每个数据成员清零”。我进行了测试,但我没有看到任何清零行为。我也没能在Google上找到任何相关信息。这是一个错误还是特定编译器的怪癖呢?
int i = int();
将使得i == 0
。 - wilhelmtellClass(Class&&) = default;
来强制创建默认版本。如果您定义了任一移动操作,则必须同时定义两个。 - Martin York我认为值得指出的是,如果您没有提供任何构造函数,编译器才会创建默认构造函数。这意味着,如果您只提供了一个带有参数的构造函数,编译器将不会为您创建默认的无参数构造函数。
你的书讨论的清零行为可能是特定于某个编译器。我一直认为它可能会有所不同,因此您应该显式初始化任何数据成员。
- 编译器会自动生成默认构造函数吗?
- 隐式生成的默认构造函数是否执行零初始化?
如果您严格解析2003标准的语言,那么答案是是和否。然而,这并不是全部内容,因为与用户定义的默认构造函数不同,在从头创建对象时,并非总是使用隐式定义的默认构造函数 - 存在两种其他情况: 无构造 和 成员值初始化。
"无构造" 的情况实际上只是技术性问题,因为它在功能上与调用 平凡 默认构造函数没有什么区别。另一种情况更有趣:成员值初始化是通过使用 "()" [就像显式调用没有参数的构造函数] 来调用的,并且它绕过了技术上称为 默认构造函数 的内容。相反,它在每个数据成员上递归执行值初始化,并对于原始数据类型,这最终解析为零初始化。
因此,实际上,编译器提供了两种不同的隐式定义的默认构造函数。其中一个执行原始成员数据的零初始化,另一个则不执行。以下是如何调用每种类型构造函数的一些示例:
MyClass a; // default-construction or no construction
MyClass b = MyClass(); // member-wise value-initialization
并且
new MyClass; // default-construction or no construction
new MyClass(); // member-wise value-initialization
If you don't declare a constructor, the compiler implicitly creates a default constructor [12.1-5]
The default constructor does not initialize primitive types [12.1-7]
MyClass() {} // implicitly defined constructor
If you initialize an object with "()", this does not directly invoke the default constructor. Instead, it instigates a long sequence of rules called value-initialization [8.5-7]
The net effect of value initialization is that the implicitly declared default constructor is never called. Instead, a recursive member-wise value initialization is invoked which will ultimately zero-initialize any primitive members and calls the default constructor on any members which have a user-declared constructor [8.5-5]
Value-initialization applies even to primitive types -- they will be zero-initialized. [8.5-5]
int a = int(); // equivalent to int a = 0;
对于大多数情况来说,这一切都是无关紧要的。类的编写者通常不能假设数据成员会在隐式初始化序列期间被清零——因此,任何自管理的类如果有任何需要初始化的原始数据成员都应该定义自己的构造函数。
那么什么时候这很重要呢?
There may be circumstances where generic code wants to force initialization of unknown types. Value-initialization provides a way to do this. Just remember that implicit zero-initialization does not occur if the user has provided a constructor.
By default, data contained by std::vector is value-initialized. This can prevent memory debuggers from identifying logic errors associated with otherwise uninitialized memory buffers.
vector::resize( size_type sz, T c=T() ); // default c is "value-initialized"
Entire arrays of primitives type or "plain-old-data" (POD)-type structures can be zero-initialized by using value-initialization syntax.
new int[100]();
C++会生成一个默认构造函数,但仅当您没有提供自己的构造函数时才会生成。标准对数据成员清零不做要求,在首次构造任何对象时,默认它们是未定义的。
这可能会令人困惑,因为大多数C ++原始类型确实具有默认的“构造函数”,可以将它们初始化为零(例如int(),bool(),double(),long(),等)。但编译器不会调用它们来初始化POD成员,就像它为对象成员所做的那样。
值得注意的是,STL 确实 使用这些构造函数来默认构造容纳原始类型的容器的内容。您可以查看此问题以获取有关STL容器中如何初始化事物的更多详细信息。
类的默认构造函数不会初始化内置类型,但它会调用所有用户定义成员的默认构造函数:
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.
}
仅在全局范围内声明的变量会被清零。因此,如果您的对象在全局作用域中声明,它的成员将被清零:
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
}
C++不保证清零内存。Java和C#会(可以这么说)。
有些编译器可能会清零,但不要依赖它。
http://en.cppreference.com/w/cpp/language/default_constructor