我打算调用initializer_list构造函数,如果存在,则事先调用复制构造函数:为什么?
I intend to call initializer_list constructor, and copy constructor is called beforehand if it exists: why?
以下类型有三个构造函数。请注意,其中一个采用相同类型的元素的初始值设定项列表。
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
复制。
- 获取从C++中同一类中的构造函数调用的方法返回的值
- 从具有按值捕获的 lambda 移动构造 std::函数时,移动构造函数调用两次
- 确保所有构造函数调用相同的函数 c++ 设计模式
- 减少复制构造函数调用
- 使用回调函数从构造函数调用虚拟/派生方法的替代方法?
- 在 Google 测试中,我可以从构造函数调用 GetParam() 吗?
- C++ - 从另一个类构造函数调用类构造函数
- 在C++中初始化带有和不使用构造函数调用的对象有什么区别
- 是否可以从移动构造函数调用默认构造函数?
- 在模板生成器模式中分解重复的构造函数调用
- std::atexit 从全局对象的构造函数调用时的排序
- 对构造函数调用的约束
- 编译器错过了无效的构造函数调用,并调用不存在的(或私有的)默认构造函数
- 用构造函数调用填充向量
- 创建指针时是否没有构造函数调用
- 使用 emplace_back 避免移动构造函数调用的最佳方法?
- C++ 抽象类构造函数调用
- 为什么函数参数将带有参数的构造函数调用
- 为什么比“构造函数”调用更多的“解构器”调用
- 将对象传递给函数并不是导致构造函数调用