GCC版本差异下数组成员变量移动构造编译异常问题咨询
GCC版本差异导致的移动构造函数编译错误分析
问题现象
- 在GCC++ <= 9.3版本中,编译以下代码会触发已删除的移动构造函数被调用的错误,具体报错信息:
: In constructor 'Widget::Widget()': :16:24: error: use of deleted function 'Child::Child(Child&&)' 16 | Widget() : m_array{} {} | ^ :11:5: note: declared here 11 | Child(Child&&) = delete; | ^~~~~
- 在GCC++ > 9.3版本中,该编译错误不再出现;另外,若注释掉基类
Base的虚析构函数,旧版本GCC的错误也会消失。
核心疑问
这是编译器特定问题还是代码本身存在问题?
相关代码
class Base { public: Base() {} virtual ~Base() = default;//注释掉此行后错误不再出现 Base(Base&&) = delete; }; class Child : public Base{ public: Child() = default; Child(Child&&) = delete; }; class Widget { public: Widget() : m_array{} {} private: Child m_array[2]; }; int main() { Widget wd{}; }
问题分析与结论
这是GCC 9.3及更早版本的编译器bug,代码本身完全符合C++标准,不存在问题。
具体原因
- C++标准规定:
Widget构造函数中m_array{}属于数组的值初始化,对于数组里的每个Child对象,应该调用其默认构造函数完成初始化——Child显式默认了默认构造函数,且Base的默认构造函数可用,完全满足初始化条件。 - 旧版GCC的错误逻辑:当基类
Base存在虚析构函数时,GCC 9.3及更早版本错误地尝试调用Child已删除的移动构造函数来初始化数组元素,违背了标准规则。 - 错误消失的两种场景:
- GCC 10及以上版本修复了这个bug,会正确调用默认构造函数;
- 注释掉
Base的虚析构函数后,旧版GCC的错误触发条件消失,因此不再报错。
内容的提问来源于stack exchange,提问作者chuong vo
相关产品推荐
相关产品推荐

