我打算调用initializer_list构造函数,如果存在,则事先调用复制构造函数:为什么?

I intend to call initializer_list constructor, and copy constructor is called beforehand if it exists: why?

本文关键字:构造函数 调用 复制 为什么 存在 initializer list 如果      更新时间:2023-10-16

以下类型有三个构造函数。请注意,其中一个采用相同类型的元素的初始值设定项列表。

struct Foo {
Foo() {
std::cout << "default ctor" << std::endl;
}
Foo(const Foo&) {
std::cout << "copy ctor" << std::endl;
}
Foo(std::initializer_list<Foo>) {
std::cout << "initializer_list<Foo>" << std::endl;
}
};

在使用initializer_list初始化对象时,我惊讶地看到复制构造函数被自动调用的次数与initializer_list中的元素一样多。之后,initializer_list构造函数称为:

int main()
{
Foo a;          // default ctor
Foo b{a, a, a}; // copy ctor + copy ctor + copy ctor + initializer_list<Foo>
return 0;
}

这种行为背后的原因/理由是什么?请注意,如果 Foo 没有复制构造函数,则初始化Foo b{a, a, a}显然是完全可能的(initializer_list构造函数将是唯一调用的构造函数(。

完整代码在这里:http://coliru.stacked-crooked.com/a/f6e28dbb66746aa2

这种行为背后的原因/理由是什么?

表达式{a, a, a}(在您的示例中(构造一个std::initializer_list<Foo>

该数组的每个元素(是的,您可以像轻量级数组一样使用初始值设定项列表(都构造为对象a的副本

实际上,该类的复制构造函数被调用三次,以便恰好构造三个副本。


请注意,如果Foo没有复制构造函数,则初始化Foo b{a,a,a}显然是完全可能的(initializer_list构造函数将是唯一调用的构造函数(。

这不是真的。如果Foo"没有复制构造函数",编译器将提供一个默认构造函数。因此,在这种情况下,复制构造函数仍将被调用三次,如前面的示例所示。

您只需删除默认的复制构造函数即可证明这一点。

从您的示例中:

struct Bar {
// ...
Bar(const Bar&) = delete;
};

这样,就没有复制构造函数,并且代码不会因为错误而编译:

use of deleted function 'Bar::Bar(const Bar&)'
std::cout << "d : "; Bar d{c, c, c};

实际上,不可能像往常一样构造初始值设定项列表。


结语

这并不神秘。 你想要构造一个包含三个对象的"列表"。编译器必须构造这些对象,从a复制。