不可复制类数据成员的统一初始化导致gcc错误
Uniform initialization of non-copiable class data member cause to gcc error
假设我们有这样的代码:
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错误吗?(我在GodPolt.org上试过所有GCC版本,都有同样的错误。(
这是一个GCC错误。
B
的默认构造函数使用聚合初始化来初始化a
,而不使用初始化器。[dcl.init.agr]/8:
如果列表中的初始值设定项子句少于非并集聚合中的元素,则每个元素都不是显式的初始化如下:
如果元素有默认的成员初始值设定项([class.mem](,则从该初始值设定值初始化元素。
否则,如果该元素不是引用,则从空的初始值设定项列表([dcl.init.list](复制初始化该元素
否则,程序就是格式错误的。
[…]
因此a[0]
是从{}
复制初始化的,这是复制列表初始化。这可能是GCC开始感到困惑的地方—复制初始化不一定涉及复制构造函数。
[dcl.init.list]/3.4:
T
类型的对象或引用的列表初始化定义为如下:
[…]
否则,如果初始值设定项列表没有元素,并且
T
是具有默认构造函数的类类型,则对象为值已初始化。[…]
因此,直接使用A
的默认构造函数。不涉及复制构造函数。也不是琐碎。
如果您担心C++11和C++17之间的差异,N3337[dcl.init.agr]/7:
如果列表中的初始值设定项子句少于聚合中的成员,然后每个成员未显式初始化应该从一个空的初始化器列表([dcl.init.list](初始化。[…]
此处甚至不涉及复制初始化。和N3337[dcl.init.list]/3.1:
定义了类型为
T
的对象或引用的列表初始化如下所示:
如果初始值设定项列表没有元素,并且
T
是具有默认构造函数的类类型,则对象被值初始化。[…]
没有变化。
- 初始化迭代器错误 C++ 在 GCC 编译器中
- 为什么 gcc 会给我可能未初始化的警告 deque::insert 带有过滤范围
- GCC 匿名是未初始化的
- 为什么数组的 GCC 聚合初始化首先用零填充整个事物,包括非零元素?
- 为什么 gcc 警告只针对统一初始化缩小转换范围?
- 不可复制类数据成员的统一初始化导致gcc错误
- 如何在macOS中的旧扩展clang和gcc编译器中初始化数组和向量
- 你能初始化unique_ptrs "static const vectors"吗?(C++17 与 GCC 7.3)
- 如何实现使用 gcc-4.4 编译的大向量初始化?
- thread_local静态成员模板定义:初始化失败,GCC
- 初始化不可移动对象数组:为什么这样的代码无法在 GCC 上编译?
- 使用GCC 4.8构建错误:数组用作初始化器
- 为什么 GCC 6.3 在没有显式 C++11 支持的情况下编译此大括号初始化列表代码
- C++指向成员的指针的类内初始化会使 MSVC 失败(但 GCC/Clang 工作)
- 告诉 GCC 假设对象已初始化
- GCC缺少优化CTOR初始化器列表的机会
- 与lambda一起使用虚拟继承在初始化列表中捕获此问题的GCC错误
- GCC允许允许非初始化的ConstexPR
- 没有临时数组的列表初始化 - 在 GCC 中不起作用
- std::make_shared是否执行值初始化(GCC和clang不同意)