假设我们有以下代码:
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版本,出现相同的错误。)
最佳答案
这是一个GCC错误。B
的默认构造函数使用聚合初始化来初始化无初始化程序的a
。 [dcl.init.aggr]/8:
If there are fewer initializer-clauses in the list than there are elements in a non-union aggregate, then each element not explicitly initialized is initialized as follows:
If the element has a default member initializer ([class.mem]), the element is initialized from that initializer.
Otherwise, if the element is not a reference, the element is copy-initialized from an empty initializer list ([dcl.init.list]).
Otherwise, the program is ill-formed.
[...]
因此,
a[0]
是从{}
复制副本初始化的,它是copy-list-initialization。这可能是GCC开始感到困惑的地方-复制初始化不一定涉及复制构造函数。[dcl.init.list]/3.4:
List-initialization of an object or reference of type
T
is defined as follows:
[...]
Otherwise, if the initializer list has no elements and
T
is a class type with a default constructor, the object is value-initialized.[...]
因此,直接使用
A
的默认构造函数。没有涉及复制构造函数。也不琐碎。如果您担心C++ 11和C++ 17之间的区别,请N3337 [dcl.init.aggr]/7:
If there are fewer initializer-clauses in the list than there are members in the aggregate, then each member not explicitly initialized shall be initialized from an empty initializer list ([dcl.init.list]). [...]
复制初始化在这里甚至都不涉及。和N3337 [dcl.init.list]/3.1:
List-initialization of an object or reference of type
T
is defined as follows:
If the initializer list has no elements and
T
is a class type with a default constructor, the object is value-initialized.[...]
没变。
关于c++ - 不可复制类数据成员的统一初始化导致gcc错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58726018/