内置类型的成员是否默认初始化?

时间:2023-01-15 19:00:23

I recently ran into a problem with one of my classes because I hadn't set a pointer to NULL in my constructor initialiser list and so it contained rubbish when I ran the program.

我最近遇到了我的一个类的问题,因为我没有在构造函数初始化列表中设置指向NULL的指针,因此当我运行程序时它包含垃圾。

However, whilst I know that instances of a built-in type declared on the stack but not initialised will contain random values, I was pretty sure I'd read somewhere that as class members not placed explicitly in the constructor initialiser list would have their default constructors called, for built-in types this would occur too, inserting code like a pseudo-constructor that will on most platforms, set them to zero I also thought I'd read in 'Thinking in C++' somewhere that under certain circumstances before an object is constructed its memory will be zeroed-out, however I appear to be wrong on both occasions.

但是,虽然我知道在堆栈上声明但未初始化的内置类型的实例将包含随机值,但我非常确定我会读到某个地方,因为未在构造函数初始化列表中明确放置的类成员将具有其默认值对于内置类型调用的构造函数,这也会发生,插入像大型平台上的伪构造函数的代码,将它们设置为零我也认为我在某些情况下在某些情况下读到了“在C ++中思考”构造对象的内存将被清零,但在两种情况下我似乎都是错误的。

Please could anyone confirm for me,
a) Does initialisation of members of a built-in type have anything to do with whether a user-defined constructor is defined or not,
b) do members of a built-in type always need to be initialised manually, and
c) are there any circumstances under which an object's storage is zeroed-out before the constructor is called?

请有人确认一下,a)内置类型成员的初始化与是否定义了用户定义的构造函数有关,b)是否需要初始化内置类型的成员手动,和c)是否有任何情况下,在调用构造函数之前,对象的存储被清零?

Also, in researching this, I have seen the terms 'default-initialised' and 'zero-initialised' used - is there a difference between saying:

此外,在研究这个问题时,我已经看到使用“default-initialised”和“zero-initialised”这两个术语 - 说:

T a;

and

T a();

? I thought that the first form was just used to prevent ambiguity when the second may be taken by the compiler as a function declaration.

?我认为第一种形式只是用于防止模糊,当第二种形式可以被编译器作为函数声明。

Thank you very much for your time,

非常感谢您的宝贵时间,

stellarpower

3 个解决方案

#1


12  

First let's go over some examples and the correct terminology.

首先让我们来看一些例子和正确的术语。

T a1;            // default initialization
T a2{};          // value initialization
T();             // also value initialization
new T;           // default initialization
new T();         // value initialization
new T{};         // also value initialization
class C1 {
    C1() {}
    T x;
};               // no initializer for C1::x; default-initialized
class C2 {
    T x;
};               // implicit default constructor default-initializes C2::x
class C3 {
    C3() : x() {}
    T x;
};               // C3::x will be value-initialized.
class C4 {
    C4() : x{} {}
    T x;
};               // C4::x will also be value-initialized.
// DANGER
T a();           // declares a function; not value initialization (quirk of C++)

Generally, the rule is that when there is no initializer, it is default initialization, and when the initializer is () or {}, it is value initialization. Note that there is an exception for statics and thread-locals, which I'll discuss later.

通常,规则是当没有初始化器时,它是默认初始化,当初始化器是()或{}时,它是值初始化。请注意,静态和线程局部有一个例外,我将在后面讨论。

For an integer or floating-point type, value initialization sets it to 0. For a pointer type, value initialization sets it to null. Default initialization does nothing for scalar types. Therefore, if an object of scalar type only receives default initialization, then it has indeterminate value.

对于整数或浮点类型,值初始化将其设置为0.对于指针类型,值初始化将其设置为null。默认初始化对标量类型没有任何作用。因此,如果标量类型的对象仅接收默认初始化,则它具有不确定的值。

a) Does initialisation of members of a built-in type have anything to do with wheher a user-defined constructor is defined or not,

a)内置类型成员的初始化与定义或不定义用户定义的构造函数有关,

The default constructor for a class default-initializes members. A member is also default-initialized when no mem-initializer is explicitly provided for it. The examples C1 and C2 illustrate this. However, note that when a class type is value-initialized, and the class's default constructor is either implicitly defined or explicitly defaulted, the class's members will be zeroed out. This zeroing out occurs only in this case, and doesn't occur for a user-provided default constructor. So the answer to your question is "yes" in this sense.

类的默认构造函数default-initializes成员。当没有为其明确提供mem-initializer时,也会默认初始化成员。示例C1和C2说明了这一点。但是,请注意,当类类型进行了值初始化,并且类的默认构造函数被隐式定义或显式默认时,类的成员将被清零。此归零只在这种情况下发生,并且不会发生在用户提供的默认构造函数中。因此,从这个意义上说,你的问题的答案是肯定的。

C1 y1;   // y1 is default-initialized; y1.x is indeterminate
C1 y2{}; // y2 is value-initialized;   y2.x is indeterminate
C2 y3;   // y3 is default-initialized; y3.x is indeterminate
C2 y4{}; // y4 is value-initialized;   y4.x is set to 0
C3 y5;   // y5 is default-initialized; y5.x is set to 0
C3 y6{}; // y6 is value-initialized;   y6.x is set to 0

b) do members of a built-in type always need to be initialised manually, and c) are there any circumstances under which an object's storage is zeroed-out before the constructor is called?

b)内置类型的成员是否总是需要手动初始化,以及c)是否存在在调用构造函数之前对象的存储被清零的任何情况?

I assume you mean "class members with built-in type". I covered a case above in which they are automatically initialized to 0: where the class object is value-initialized and its constructor is not user-provided (or deleted). Another case is when the class object has static or thread-local storage duration. In this case, the members will also be zeroed out at the very beginning, so there is no chance of them ending up with indeterminate value.

我假设你的意思是“具有内置类型的类成员”。我在上面介绍了一个案例,其中它们被自动初始化为0:其中类对象是值初始化的,其构造函数不是用户提供的(或删除的)。另一种情况是类对象具有静态或线程本地存储持续时间。在这种情况下,成员也会在一开始就归零,因此他们没有机会以不确定的价值结束。

#2


1  

The term you are looking for is default initialized. Any instance data member will be default initialized if it is not explicitly initialized in the body of the constructor. What this means depends on whether the data member is a primitive data type or not and where the object instantiation takes place. In case of data members of non-primitive data types, the default constructor will be used (or the compiler will complain if there is no default constructor). In case of data members of primitive data types this means that they will not be initialized if the instantiation takes place on the stack or on the heap. If it is a global or a static variable however, the data members will be set to 0.

您要查找的术语是默认初始化的。如果未在构造函数体中显式初始化任何实例数据成员,则将对其进行默认初始化。这意味着什么取决于数据成员是否是原始数据类型以及对象实例化发生的位置。对于非原始数据类型的数据成员,将使用默认构造函数(或者如果没有默认构造函数,编译器将会抱怨)。对于原始数据类型的数据成员,这意味着如果实例化发生在堆栈上或堆上,则不会初始化它们。但是,如果它是全局变量或静态变量,则数据成员将设置为0。

By the way, when you write

顺便说一下,当你写作

T a;

then you define a variable a of type T. When you write

然后你定义一个类型为T的变量a。当你写

T a();

then you declare a function a() which returns T by value.

然后你声明一个函数a(),它按值返回T.

#3


1  

One way to default initialize all member variables without calling a constructor would be if you have a POD type. For e.g. this is a POD

如果您有POD类型,默认初始化所有成员变量而不调用构造函数的一种方法。对于例如这是一个POD

class Foo {
    int num1;
    double num2;
    bool b;
    int *pnum;
};

and if you do

如果你这样做

Foo foo = {};

everything will be zero-initialized (b will be false, pnum NULL etc) without calling the (default) constructor.

在不调用(默认)构造函数的情况下,所有内容都将被零初始化(b将为false,pnum为NULL等)。

So

a) a POD type must not have a user defined constructor so in that case yes

a)POD类型不能有用户定义的构造函数,所以在这种情况下是

b) if you have a POD you don't have to initialize them manually

b)如果您有POD,则无需手动初始化它们

c) if you have a POD type you can zero-initialize without calling a constructor.

c)如果你有一个POD类型,你可以在不调用构造函数的情况下进行零初始化。

Another way to create a class instance and zero-initialize without calling a constructor would be to allocate the required memory with calloc and cast the pointer to the required type. You should avoid that unless absolutely necessary!

创建类实例并在不调用构造函数的情况下进行零初始化的另一种方法是使用calloc分配所需的内存并将指针强制转换为所需的类型。除非绝对必要,否则你应该避免

#1


12  

First let's go over some examples and the correct terminology.

首先让我们来看一些例子和正确的术语。

T a1;            // default initialization
T a2{};          // value initialization
T();             // also value initialization
new T;           // default initialization
new T();         // value initialization
new T{};         // also value initialization
class C1 {
    C1() {}
    T x;
};               // no initializer for C1::x; default-initialized
class C2 {
    T x;
};               // implicit default constructor default-initializes C2::x
class C3 {
    C3() : x() {}
    T x;
};               // C3::x will be value-initialized.
class C4 {
    C4() : x{} {}
    T x;
};               // C4::x will also be value-initialized.
// DANGER
T a();           // declares a function; not value initialization (quirk of C++)

Generally, the rule is that when there is no initializer, it is default initialization, and when the initializer is () or {}, it is value initialization. Note that there is an exception for statics and thread-locals, which I'll discuss later.

通常,规则是当没有初始化器时,它是默认初始化,当初始化器是()或{}时,它是值初始化。请注意,静态和线程局部有一个例外,我将在后面讨论。

For an integer or floating-point type, value initialization sets it to 0. For a pointer type, value initialization sets it to null. Default initialization does nothing for scalar types. Therefore, if an object of scalar type only receives default initialization, then it has indeterminate value.

对于整数或浮点类型,值初始化将其设置为0.对于指针类型,值初始化将其设置为null。默认初始化对标量类型没有任何作用。因此,如果标量类型的对象仅接收默认初始化,则它具有不确定的值。

a) Does initialisation of members of a built-in type have anything to do with wheher a user-defined constructor is defined or not,

a)内置类型成员的初始化与定义或不定义用户定义的构造函数有关,

The default constructor for a class default-initializes members. A member is also default-initialized when no mem-initializer is explicitly provided for it. The examples C1 and C2 illustrate this. However, note that when a class type is value-initialized, and the class's default constructor is either implicitly defined or explicitly defaulted, the class's members will be zeroed out. This zeroing out occurs only in this case, and doesn't occur for a user-provided default constructor. So the answer to your question is "yes" in this sense.

类的默认构造函数default-initializes成员。当没有为其明确提供mem-initializer时,也会默认初始化成员。示例C1和C2说明了这一点。但是,请注意,当类类型进行了值初始化,并且类的默认构造函数被隐式定义或显式默认时,类的成员将被清零。此归零只在这种情况下发生,并且不会发生在用户提供的默认构造函数中。因此,从这个意义上说,你的问题的答案是肯定的。

C1 y1;   // y1 is default-initialized; y1.x is indeterminate
C1 y2{}; // y2 is value-initialized;   y2.x is indeterminate
C2 y3;   // y3 is default-initialized; y3.x is indeterminate
C2 y4{}; // y4 is value-initialized;   y4.x is set to 0
C3 y5;   // y5 is default-initialized; y5.x is set to 0
C3 y6{}; // y6 is value-initialized;   y6.x is set to 0

b) do members of a built-in type always need to be initialised manually, and c) are there any circumstances under which an object's storage is zeroed-out before the constructor is called?

b)内置类型的成员是否总是需要手动初始化,以及c)是否存在在调用构造函数之前对象的存储被清零的任何情况?

I assume you mean "class members with built-in type". I covered a case above in which they are automatically initialized to 0: where the class object is value-initialized and its constructor is not user-provided (or deleted). Another case is when the class object has static or thread-local storage duration. In this case, the members will also be zeroed out at the very beginning, so there is no chance of them ending up with indeterminate value.

我假设你的意思是“具有内置类型的类成员”。我在上面介绍了一个案例,其中它们被自动初始化为0:其中类对象是值初始化的,其构造函数不是用户提供的(或删除的)。另一种情况是类对象具有静态或线程本地存储持续时间。在这种情况下,成员也会在一开始就归零,因此他们没有机会以不确定的价值结束。

#2


1  

The term you are looking for is default initialized. Any instance data member will be default initialized if it is not explicitly initialized in the body of the constructor. What this means depends on whether the data member is a primitive data type or not and where the object instantiation takes place. In case of data members of non-primitive data types, the default constructor will be used (or the compiler will complain if there is no default constructor). In case of data members of primitive data types this means that they will not be initialized if the instantiation takes place on the stack or on the heap. If it is a global or a static variable however, the data members will be set to 0.

您要查找的术语是默认初始化的。如果未在构造函数体中显式初始化任何实例数据成员,则将对其进行默认初始化。这意味着什么取决于数据成员是否是原始数据类型以及对象实例化发生的位置。对于非原始数据类型的数据成员,将使用默认构造函数(或者如果没有默认构造函数,编译器将会抱怨)。对于原始数据类型的数据成员,这意味着如果实例化发生在堆栈上或堆上,则不会初始化它们。但是,如果它是全局变量或静态变量,则数据成员将设置为0。

By the way, when you write

顺便说一下,当你写作

T a;

then you define a variable a of type T. When you write

然后你定义一个类型为T的变量a。当你写

T a();

then you declare a function a() which returns T by value.

然后你声明一个函数a(),它按值返回T.

#3


1  

One way to default initialize all member variables without calling a constructor would be if you have a POD type. For e.g. this is a POD

如果您有POD类型,默认初始化所有成员变量而不调用构造函数的一种方法。对于例如这是一个POD

class Foo {
    int num1;
    double num2;
    bool b;
    int *pnum;
};

and if you do

如果你这样做

Foo foo = {};

everything will be zero-initialized (b will be false, pnum NULL etc) without calling the (default) constructor.

在不调用(默认)构造函数的情况下,所有内容都将被零初始化(b将为false,pnum为NULL等)。

So

a) a POD type must not have a user defined constructor so in that case yes

a)POD类型不能有用户定义的构造函数,所以在这种情况下是

b) if you have a POD you don't have to initialize them manually

b)如果您有POD,则无需手动初始化它们

c) if you have a POD type you can zero-initialize without calling a constructor.

c)如果你有一个POD类型,你可以在不调用构造函数的情况下进行零初始化。

Another way to create a class instance and zero-initialize without calling a constructor would be to allocate the required memory with calloc and cast the pointer to the required type. You should avoid that unless absolutely necessary!

创建类实例并在不调用构造函数的情况下进行零初始化的另一种方法是使用calloc分配所需的内存并将指针强制转换为所需的类型。除非绝对必要,否则你应该避免