使用复制列表初始化程序的 C++ 对象初始化

C++ object initialization with copy-list-initializer

// Example program
#include <iostream>
#include <string>

class T{
public:   
    int x, y;
    T(){
        std::cout << "T() constr called..." << std::endl;
    };
    T(int x, int y):x(x),y(y){
        std::cout << "T(x,y) constr called..." << std::endl;
    }
    
    void inspect(){
        std::cout << "T.x: " << this->x << std::endl;
        std::cout << "T.y: " << this->y << std::endl;
    }
};

int main()
{
    T t1(5,6);
    t1.inspect();
    
    std::cout << std::endl;
    
    T t2 = {};
    t2.inspect();
}

我得到以下结果:

T(x,y) constr called...
T.x: 5
T.y: 6

T() constr called...
T.x: 208787120
T.y: 31385

t2 实例的成员没有被零初始化(我想要实现的)。我是否理解正确,如果我定义了构造函数,它将不会执行零初始化? (我知道如何使用显式默认值实现初始化为零。问题是为什么我无法使用 init-list 做到这一点)

列表初始化

Otherwise, if the braced-init-list is empty and T is a class type with a default constructor, value-initialization is performed.

值初始化

In all cases, if the empty pair of braces {} is used and T is an aggregate type, aggregate-initialization is performed instead of value-initialization.

聚合初始化(这似乎不是我的情况,因此它没有将成员初始化为零)

An aggregate is one of the following types:

  • class type (typically, struct or union), that has
    • no user-declared constructors

什么是遗留代码最简单且不易出错的修改,我需要解决一些 class 成员在初始化之前使用的问题?

t2的数据成员有垃圾值。这是因为它们是内置类型,您没有明确地初始化它们。解决方案是:

解决方案 1:使用构造函数初始化列表

T(): x(0), y(0){
        std::cout << "T() constr called..." << std::endl;
    };

解决方案 2:使用 in-class 初始化器

int x = 0, y = 0;

这就是为什么建议

always initialize built-in type in block/local scope

如果您使用上面给出的任何解决方案,输出将是:

T(x,y) constr called...
T.x: 5
T.y: 6

T() constr called...
T.x: 0
T.y: 0

这就是你想要的并且可以看到here and here

另一种解决方案是使用委托构造函数(正如@MarekR 在下面的评论中所建议的),例如:

T():T(0, 0) 
{
    std::cout << "T() constr called..." << std::endl;
}

零初始化是一种特殊情况。该标准仅保证成员属性被 default 初始化。对于 class 对象,这确实意味着将调用默认构造函数。但是对于基本类型对象,默认初始化只是......根本没有初始化。如果需要,您必须明确要求:

T(): x(0), y(0) {
    ...

Do I understand it correctly, that if I have a constructor defined, it will not perform a zero initialization?

是的。

请注意,T 不是聚合,因为它包含用户提供的构造函数。作为value initialization的效果:

  1. if T is a class type with no default constructor or with a user-provided or deleted default constructor, the object is default-initialized;

  2. if T is a class type with a default constructor that is neither user-provided nor deleted (that is, it may be a class with an implicitly-defined or defaulted default constructor), the object is zero-initialized and then it is default-initialized if it has a non-trivial default constructor;

T包含用户提供的默认构造函数,然后应用#1(但不是#2首先执行零初始化)。

default initialization中,使用用户提供的默认构造函数来初始化对象。默认构造函数不对数据成员执行初始化,它们被初始化为不确定的值。