You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

数组无临时对象列表初始化在GCC失效:Clang与GCC谁合规?

Clang的实现符合C++标准,GCC在此场景下的处理有误

先明确结论:Clang是对的,GCC的报错不符合C++标准要求。下面我们拆解问题的核心逻辑和对应的标准规则:

问题场景回顾

我们的代码里:

  • 结构体A有一个接受int的构造函数,删除了拷贝构造函数,还有一个用户声明的析构函数
  • 结构体B是一个聚合类型(没有用户声明的构造函数、析构函数等),包含一个A类型的数组a[2],用初始化列表{{1}, {2}}初始化
  • Clang编译通过,GCC在A有析构函数时会报错说使用了被删除的拷贝构造,注释掉析构函数后编译通过

核心标准规则:聚合初始化的直接初始化语义

根据C++标准中聚合初始化([dcl.init.aggr]章节)的规则,当我们对聚合类型(这里的B就是聚合)进行初始化时,初始化列表中的每个元素会直接初始化聚合对应的成员:

  • 对于B中的数组a[2],初始化列表里的{1}会直接用来初始化a[0],也就是调用A(int)构造函数创建a[0];{2}同理直接初始化a[1]
  • 整个过程完全不需要创建临时A对象,自然也不会触发拷贝构造函数——哪怕拷贝构造被删除,也不会影响这个初始化过程

GCC错误的原因

GCC的问题在于,当A存在用户声明的析构函数时,它错误地认为数组元素的初始化需要先创建临时A对象,再通过拷贝构造完成初始化。这完全违背了聚合初始化的直接初始化语义:

  • 当注释掉A的析构函数后,A变成了更“简单”的类型,GCC可能正确识别了直接初始化的路径,所以编译通过,但这只是巧合,并非正确的标准实现
  • 无论A是否有用户声明的析构函数,聚合初始化都应该以直接初始化的方式处理数组元素,不涉及拷贝构造

关于你提到的[dcl.init.list]/5

你提到的这个条款是针对非聚合类型的列表初始化场景的,它描述的是当用列表初始化非聚合对象时可能会创建临时对象并拷贝的情况,但我们的场景是聚合初始化,适用的是[dcl.init.aggr]的规则,这个条款并不覆盖当前场景。所以你最初的判断(GCC错误)是正确的。

内容的提问来源于stack exchange,提问作者rustyx

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 05:31:12