初始化不可移动对象的数组:为什么这样的代码无法在GCC上编译?

阳台

这是代码示例,其中Test带有某些成员和用户定义的构造函数的不可复制不可移动的类virtual,并且B是包含原始(C样式)Test对象数组的类

class Test
{
public:
    Test() = delete;

    Test(const Test&) = delete;
    Test(Test&&) = delete;
    Test& operator=(const Test&) = delete;
    Test& operator=(Test&&) = delete;

    Test(int a, int b) : a_(a), b_(b) {}
    virtual ~Test() {}

    int a_;
    int b_;
};

//----------------

class B
{
public:
/*(1)*/ B() : test_{{1, 2}, {3, 4}} {} // Does not compile on GCC, but compiles on Clang and MSVC

private:
        Test test_[2];
};

//---------------- 

int main()
{
        B b;
/*(2)*/ Test test[2] = {{1, 2}, {3, 4}}; // Successfully compiles on GCC, Clang and MSVC
}

我想使用加括号的初始化语法(第行来初始化B的内部数组,这样就可以就地构造两个对象中的每个对象,而无需创建一个临时对象然后移动它。test_/*1*/Test

在Clang和MSVC上,此代码无需警告即可编译。

但是GCC的行为使我感到困惑:它无法编译行/*1*/,而成功地编译了行/*2*/,而我使用相同的语法来初始化本地数组。但是,对于编译第一行,它仍然需要删除class的move构造函数Test

问题是,为什么?C ++标准是否明确定义了这些行/*1*/是否/*2*/应该进行编译?如果可以,那么从标准的角度来看,哪个编译器是正确的?可以将这种不一致的行为称为GCC错误,还是Clang和MSVC忽略它们应该执行的某些检查?

我可以理解,GCC可能需要一个move构造函数才能Test从内部花括号({1, 2}创建一个临时对象,然后将该对象移动到数组中。因此,编译错误。但是,如果是这样的话,为什么出于同样的原因它也不会失败/*(2)*/呢?在此示例中,这是我最困惑的事情。


顺便说一句,这是一个有趣的观察:如果我将test_with的定义替换为std::array<Test, 2>(而不是“ C样式”数组),并用替换构造函数的初始化列表中的代码,则test_{{{1, 2}, {3, 4}}}所有内容将开始在上述所有三个编译器上成功编译。

我还不清楚为什么在这种情况下GCC在任何情况下都不会失败,而“原始”数组会失败。

谁能解释一下?

如果

我认为初始化没有问题,所以我认为这是一个GCC错误。


涉及的初始化是列表初始化,因此我们参考[dcl.init.list] / 3

对象或类型引用的列表初始化T定义如下:

  • [...]

  • 3.3)否则,如果T是聚合,则执行聚合初始化。

  • [...]

(数组是一个集合。)现在,我们转到[dcl.init.aggr] / 3

当按[dcl.init.list]中指定的初始化器列表初始化聚合时,初始化器列表的元素按顺序用作聚合器元素的初始化器。每个元素都是从相应的initializer-clause复制初始化的如果初始化子句是一个表达式,并且需要缩小转换范围以转换该表达式,则程序格式错误。

因此,对于这两个元素中的任何一个,我们都在有效地进行Test a = {1, 2},这是有效的,因为Test(int, int)它不是显式的。因此,初始化格式正确,应由编译器接受。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

为什么像GCC这样的编译器无法在向量上消除死代码?

为什么编译器禁止初始化数组?

无法理解为什么无法初始化对象初始化程序中的数组初始化程序

为什么使用数组初始化程序的C#代码无法重构我的期望

初始化易失性数组时,为什么编译器会生成此类代码?

为什么会出现“无法访问的代码”和“变量未初始化”的编译错误?

集合初始化中被遗忘的“新”声明:此代码做什么,为什么要编译?

为什么这个模板化函数不能对数组进行零初始化编译?

为什么无法初始化Datareader?

为什么不能在init块编译中初始化变量接口属性的代码?

为什么 GCC 不将静态初始化的 C++ 类对象放入 .data

编译错误:(1)上的Dummy无法具有初始化程序。什么是虚拟变量?

为什么在循环中初始化数组时Rust编译器为什么会给出未初始化的变量错误?

为什么在尝试使用C ++ 11样式初始化对象数组时编译器隐式删除构造函数

为什么GCC不报告未初始化的变量?

复制列表初始化?为什么会编译?

初始化静态成员使编译工作...但是为什么

为什么在初始化代码之前无法正确加载我的环境变量?

为什么我的向量初始化使数组中的所有对象都相同?

为什么类对象内的tf.Variable无法初始化?

无法使用函数的返回值初始化对象.. 为什么?

对象初始化-为什么用“:”而不是“ =”初始化对象属性

为什么没有arrays.aslist()无法用数组初始化list?

为什么不在 Java 中的未初始化数组上“为每个”循环

数组不应由数组初始化程序静态初始化。为什么?

量角器为什么无法在自动初始化的Angular站点上找到Angular?

对象数组初始化?

初始化对象数组

如果变量没有初始化,为什么这个 C 代码需要这么长时间来编译和执行?