C++ 默认构造函数

2022-01-18 00:00:00 initialization c++

给定以下代码:

class temp
{
public:
    string str;
    int num;
};

int main()
{
    temp temp1;
    temp temp2 = temp();

    cout << temp1.str << endl; //Print ""
    cout << temp2.str << endl; //Print ""

    cout << temp1.num << endl; //Print a rand num
    cout << temp2.num << endl; //Print 0
}

这两者有什么不同?—

What is the different between these two?—

temp temp1;

temp temp2 = temp();

推荐答案

temp temp1;

这会在名为 temp1 的实例上调用 temp 的默认构造函数.

This calls temp's default constructor on the instance called temp1.

temp temp2 = temp();

这会在临时对象上调用 temp 的默认构造函数,然后在 temp2 上调用编译器生成的复制构造函数,并将临时对象作为参数(this 的当然假设编译器不会删除副本;这取决于您的编译器的优化设置).

This calls temp's default constructor on a temporary object, then calls the compiler-generated copy-constructor on temp2 with the temporary object as the argument (this of course assumes that the compiler doesn't elide copies; it depends on your compiler's optimization settings).

至于为什么会得到不同的初始化值,标准的8.5节是相关的:

As for why you get different initialized values, section 8.5 of the standard is relevant:

第 5 段:

零初始化T 类型的对象意味着:

  • 如果T是标量类型(3.9),则将对象设置为值0(零)转换为T
  • 如果 T 是非联合类类型,则每个非静态数据成员和每个基类子对象都初始化为零;
  • 如果 T 是联合类型,则对象的第一个命名数据成员为零初始化;
  • 如果T是数组类型,每个元素都初始化为零;
  • 如果 T 是引用类型,则不执行初始化.
  • if T is a scalar type (3.9), the object is set to the value of 0 (zero) converted to T;
  • if T is a non-union class type, each nonstatic data member and each base-class subobject is zero-initialized;
  • if T is a union type, the object’s first named data member is zero-initialized;
  • if T is an array type, each element is zero-initialized;
  • if T is a reference type, no initialization is performed.

默认初始化类型为T的对象意味着:

  • 如果 T 是非 POD 类类型(第 9 条),则调用 T 的默认构造函数(如果 T 没有可访问的默认构造函数);
  • 如果T是数组类型,每个元素都是默认初始化的;
  • 否则,对象被零初始化.
  • if T is a non-POD class type (clause 9), the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
  • if T is an array type, each element is default-initialized;
  • otherwise, the object is zero-initialized.

T类型的对象进行值初始化意味着:

To value-initialize an object of type T means:

  • 如果 T 是具有用户声明的构造函数 (12.1) 的类类型(第 9 条),则调用 T 的默认构造函数(初始化为如果 T 没有可访问的默认构造函数,则格式错误);
  • 如果 T 是没有用户声明的构造函数的非联合类类型,则 T 的每个非静态数据成员和基类组件都是值初始化的;
  • 如果T是数组类型,那么每个元素都是值初始化的;
  • 否则,对象被零初始化.
  • if T is a class type (clause 9) with a user-declared constructor (12.1), then the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
  • if T is a non-union class type without a user-declared constructor, then every non-static data member and base-class component of T is value-initialized;
  • if T is an array type, then each element is value-initialized;
  • otherwise, the object is zero-initialized.

第 7 段:

初始化器为空括号集的对象,即 (),应进行值初始化.

Paragraph 7:

An object whose initializer is an empty set of parentheses, i.e., (), shall be value-initialized.

第 9 段:

如果没有为对象指定初始化程序,并且该对象是(可能是 cv 限定的)非 POD 类类型(或其数组),则该对象应为默认值-初始化;如果对象是 const 限定类型,则基础类类型应具有用户声明的默认构造函数.否则,如果没有为非静态对象指定初始化器,则该对象及其子对象(如果有)具有不确定的初始值;如果对象或其任何子对象是 const 限定类型,则程序是非良构的.

Paragraph 9:

If no initializer is specified for an object, and the object is of (possibly cv-qualified) non-POD class type (or array thereof), the object shall be default-initialized; if the object is of const-qualified type, the underlying class type shall have a user-declared default constructor. Otherwise, if no initializer is specified for a nonstatic object, the object and its subobjects, if any, have an indeterminate initial value; if the object or any of its subobjects are of const-qualified type, the program is ill-formed.

第 7 段:

隐式声明的类默认构造函数在用于创建其类类型 (1.8) 的对象时被隐式定义.隐式定义的默认构造函数执行类的一组初始化,这些初始化将由用户编写的具有空 mem-initializer-list (12.6.2) 和空函数体的类的默认构造函数执行.

Paragraph 7:

An implicitly-declared default constructor for a class is implicitly defined when it is used to create an object of its class type (1.8). The implicitly-defined default constructor performs the set of initializations of the class that would be performed by a user-written default constructor for that class with an empty mem-initializer-list (12.6.2) and an empty function body.

第 4 段:

如果给定的非静态数据成员或基类不是由 mem-initializer-id 命名的(包括没有 mem-initializer-list 的情况,因为构造函数没有ctor-initializer),然后

Paragraph 4:

If a given nonstatic data member or base class is not named by a mem-initializer-id (including the case where there is no mem-initializer-list because the constructor has no ctor-initializer), then

  • 如果实体是(可能是 cv 限定的)类类型(或其数组)或基类的非静态数据成员,并且实体类是非 POD 类,则实体是默认初始化的 (8.5).如果实体是 const 限定类型的非静态数据成员,则实体类应具有用户声明的默认构造函数.
  • 否则,实体不会被初始化.如果实体是 const 限定类型或引用类型,或者是(可能是 cv 限定的)POD 类类型(或其数组),包含(直接或间接)const 限定类型的成员,则程序是 ill-形成.

既然已经制定了规则,让我们看看它们是如何应用的:

So now that the rules have been laid out, let's see how they apply:

temp temp1;

temp 是非 POD 类型(因为它有一个 std::string 成员),并且因为没有为 temp1,它将被默认初始化(8.5/9).这将调用默认构造函数 (8.5/5).temp 有一个隐式默认构造函数 (12/7),它默认初始化 std::string 成员并且 int 成员未初始化完全没有(12.6.2/4).

temp is a non-POD type (because it has a std::string member), and since no initializer is specified for temp1, it will be default-initialized (8.5/9). This calls the default constructor (8.5/5). temp has an implicit default constructor (12/7) which default-initializes the std::string member and the int member isn't initialized at all (12.6.2/4).

temp temp2 = temp();

另一方面,临时temp对象是值初始化的(8.5/7),它对所有数据成员进行值初始化(8.5/5),它调用std::string 成员并将 int 成员 (8.5/5) 初始化为零.

On the other hand, the temporary temp object is value-initialized (8.5/7), which value-initializes all data members (8.5/5), which calls the default constructor in the std::string member and zero-initializes the int member (8.5/5).

当然,如果您不想在超过 5 个不同的地方引用标准,只需确保明确初始化所有内容(例如 int i = 0; 或使用初始化列表).

Of course, if you much rather not have to refer to the standard in 5+ different places, just ensure that you explicitly initialize everything (e.g. int i = 0; or using initializer lists).

相关文章