不可复制类数据成员的统一初始化会导致gcc错误

假设我们有以下代码:

class A {
public:
    A() = default;    
    A(const A&) = delete;
    ~A() = default;
};

class B {
public:    
    B() : a{} { }    
    A a[1];
};

int main() 
{
    B b;
}

此代码在最新的GCC 9.2,Clang 9.2和MSVC 19.22上编译。

但是当我将默认析构函数更改为~A() { }时,GCC返回错误use of deleted function 'A::A(const A&)'。 Clang和MSVC仍然可以编译。

当我编写A的副本构造函数时,GCC会编译,但是在运行时从未调用过该构造函数。 GCC需要复制构造函数做什么? 是GCC错误吗? (我已经在GodBolt.org上尝试过所有GCC版本,出现相同的错误。)

linguohan 回答:不可复制类数据成员的统一初始化会导致gcc错误

这是一个GCC错误。

B的默认构造函数使用聚合初始化来初始化a,而没有初始化程序。 [dcl.init.aggr]/8

  

如果列表中的初始化器子句少于   非联盟集合中的元素,那么每个元素都不会显式   初始化如下:

     
      
  • 如果元素具有默认的成员初始化程序([class.mem]),则从该初始化程序初始化该元素。

  •   
  • 否则,如果该元素不是引用,则从一个空的初始值设定项列表([dcl.init.list])复制该元素。

  •   
  • 否则,程序格式不正确。

  •   
     

[...]

因此a[0]{}副本初始化,它是 copy-list-initialization 。这可能是GCC开始感到困惑的地方-复制初始化不一定涉及复制构造函数。

[dcl.init.list]/3.4

  

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

     
      
  • [...]

  •   
  • 否则,如果初始化列表中没有元素,并且T是具有默认构造函数的类类型,则对象为   值初始化。

  •   
  • [...]

  •   

因此,直接使用A的默认构造函数。没有涉及复制构造函数。也不琐碎。


如果您担心C ++ 11和C ++ 17之间的差异,N3337 [dcl.init.aggr]/7

  

如果列表中的初始化器子句少于   成员,然后未明确初始化的每个成员   应从一个空的初始化程序列表([dcl.init.list])进行初始化。   [...]

这里甚至不涉及复制初始化。还有N3337 [dcl.init.list]/3.1

  

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

     
      
  • 如果初始化列表中没有元素,并且T是具有默认构造函数的类类型,则该对象将被值初始化。

  •   
  • [...]

  •   

没有变化。

本文链接:https://www.f2er.com/3153879.html

大家都在问