首页 > 解决方案 > 为什么必须复制 std::initializer_list 的元素?

问题描述

cppreference 说:

底层数组是一个 const T[N] 类型的临时数组,其中每个元素都是从原始初始化列表的相应元素复制初始化的(除了缩小转换无效)。底层数组的生命周期与任何其他临时对象相同,只是从数组初始化一个 initializer_list 对象可以延长数组的生命周期,就像将引用绑定到临时对象一样(有相同的例外,例如初始化非-静态类成员)。底层数组可以分配在只读存储器中。

这个决定背后的原因是什么?为什么移动不正常?

复制省略怎么办?

struct A { A(const A&){ std::cout << "Oh no, a copy!\n"; } };
struct B { B(std::initializer_list<A> il); };

int main()
{
    B b{ A{} };
    return 0;
}

我的编译器省略了副本。但是这些副本能保证被删除吗?

标签: c++move-semanticsinitializer-list

解决方案


C ++中的“复制初始化”并不意味着必须复制事物。它只是将发生初始化的约束的正式名称。例如,在复制初始化时,显式 c'tors 不是候选对象。所以下面的代码格式不正确

#include <iostream>
#include <initializer_list>

struct A {
    explicit A() = default;
    A(const A&){ std::cout << "Oh no, a copy!\n"; } 
};
struct B { B(std::initializer_list<A> il); };

int main()
{
    B b{ {} };
    return 0;
}

列表中的单个成员需要从 复制初始化{},这需要调用默认 c'tor。但是,由于 c'tor 被标记为显式,因此无法进行此初始化。

复制省略在 C++17 之前当然是可能的,并且在 C++17 以后的某些上下文中是强制性的。在您的示例中,在 C++17 编译器下,由于您提供了一个纯右值(纯右值,而不是对象)的初始化程序,因此 C++ 的初始化规则要求直接初始化目标,而不创建中间对象。即使上下文被称为“复制初始化”,也没有多余的对象。


推荐阅读