6

几天前我发现了统一初始化,我到处都看到每个人都应该尽可能地使用它。

但是,我不禁认为这种新语法比它的价值更麻烦......


第一个例子

假设我编写了一个库,其中有一个这样的结构:

struct MyStruct
{
    int member0;
    int member1;
}

用户可以使用聚合初始化编写类似这样的内容:

MyStruct myVar = {0, 1}; // member0 = 0 and member1 = 1

现在,假设我更新了我的库,并且结构现在看起来像这样:

struct MyStruct
{
    int member0;
    int member1;

    MyStruct(int p0, int p1) : member0(p1), member1(p0){}
}

在 C++11 之前,用户代码会停止编译,这将迫使用户重写他的代码并使用构造函数。但是现在,代码将编译并被解释为统一初始化:

MyStruct myVar = {0, 1}; // member0 = 1 and member1 = 0

在用户不知道的情况下,更新他的库会使他的代码做一些非常不同的事情!


第二个例子

现在,让我们说我的图书馆中有这样的课程:

class MyClass
{
public:
    MyClass(int size, int default = 0) : elements(size, default){}
private:
    std::vector<int> elements;
}

用户可以像这样使用它:

MyClass myVar (3,1);  // 3 elements with value 1

或者,使用统一初始化,如下所示:

MyClass myVar {3,1};  // 3 elements with value 1

再说一次,让我们说我更新了我的图书馆。类现在看起来像这样:

class MyClass
{
public:
    MyClass(int size, int default = 0) : elements(size, default){}
    MyClass(std::initializer_list<int> elts) : elements(elts){}
private:
    std::vector<int> elements;
}

如果使用经典构造函数不会有问题:

MyClass myVar (3,1);  // 3 elements with value 1

但是如果调用统一初始化,代码解释将会改变:

MyClass myVar {3,1};  // 2 elements with values 3 and 1

基于这些示例,在我看来,用户使用统一初始化是极其危险的,因为当将内容添加到使用的库时,代码解释可能会发生变化,而根本没有任何警告。

更糟糕的是,统一初始化的引入使聚合初始化变得危险。

我错过了什么吗?是否存在使用统一初始化既安全又有用的情况?

4

1 回答 1

8

我认为您解决的两个问题与统一初始化本身几乎没有关系,但说明了更改接口的危险。

您可以通过像这样更新您的库来归档用户代码中非常相同的次优更改:

struct MyStruct
{
    int member1;
    int member0;
}

不涉及统一初始化。在 c++11 之前,也可以更改重载决议选择的构造函数:

class some_class
{
    public:
    some_class(int);
}

用户编码:

some_class var(1.0);

如果代码更改为:

class some_class
{
    public:
    some_class(int);
    some_class(double);
}

将调用第二个构造函数。同样,没有涉及统一初始化,但同样的问题发生了。

因此,虽然这两个示例都展示了用户代码的含义可以通过更改库接口来更改的事实,但这不是统一初始化引入或特定于统一初始化的问题,而是次优设计。它只是说明了应该非常仔细地设计库接口这一事实。

相反,统一初始化提供了一些真正的优势。对于那些,请参阅这个出色的答案

于 2014-05-04T13:39:37.347 回答