当前位置: 首页 > 知识库问答 >
问题:

不可共性类数据成员的统一初始化导致 gcc 错误

公冶浩慨
2023-03-14

假设我们有这样的代码:

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、叮当 9.2 和 MSVC 19.22 上编译。

但当我将默认析构函数更改为~A(){}GCC返回错误使用删除的函数'A::A(const A

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


共有1个答案

王嘉木
2023-03-14
匿名用户

这是一个海湾合作委员会的错误。

B的默认构造函数使用聚合初始化来初始化不带初始值设定项的。[dcl.init.aggr]/8:

如果列表中的initializer子句比非联合聚合中的元素少,则每个未显式初始化的元素都按如下方式初始化:

>

  • 如果元素有一个默认的成员初始值设定项([class.mem]),那么该元素将从该初始值设定值设定项初始化。

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

    否则,程序格式不正确。

    [...]

    所以< code>a[0]是从< code>{}复制初始化的,这是复制列表初始化。这可能是GCC开始感到困惑的地方——复制初始化不一定涉及复制构造函数。

    [dcl.init.list]/3.4:

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

    > < li>

    [...]

    否则,如果初始值设定项列表没有元素,并且 T 是具有默认构造函数的类类型,则该对象将进行值初始化。

    [...]

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

    如果您担心C11和C17之间的差异,N3337[dcl.init.aggr]/7:

    如果列表中的初始值设定项子句少于聚合中的成员数,则每个未显式初始化的成员都应从空的初始值设定项列表 ([dcl.init.list]) 初始化。[...]

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

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

    >

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

    [...]

    没有变化。

  •  类似资料:
    • 问题内容: 我最近刚与Python中的一个错误作斗争。那是那些愚蠢的新手错误之一,但是它让我思考了Python的机制(我是C ++的老程序员,是Python的新手)。我将列出错误的代码并解释如何解决该问题,然后我有两个问题。 场景:我有一个叫做A的类,它有一个字典数据成员,下面是其代码(当然这是简化的): 使用此代码的类为B类: 请注意,每次调用都会初始化类A的新“干净”实例,并在添加前后打印字典

    • 在C++98标准里,只有static const声明的整型成员能在类内部初始化,并且初始化值必须是常量表达式。这些限制确保了初始化操作可以在编译时期进行。例如: int var = 7; class X { static const int m1 = 7; // 正确 const int m2 = 7; // 错误:无static static int m3 =

    • 我正在尝试为大学的一个项目和几个学生一起建立一个Springmvc应用程序,这是一本基于网络的烹饪书。 虽然Hello World工作正常,但我们使用hibernate存储数据的代码出现了一些困难的异常。 域类: 服务类: 控制器类: 我们使用基于eclipse的Spring工具包sdk并在启动过程中获得以下异常: VMware vFabric tc Runtime 2.9.3.Release/7

    • 初始化类成员的确切时间? 在下面的代码中: B&C类的对象是什么时候创建的?并且它是否保证被创建? 一个专业的app到底该不该用这样的代码?

    • 考虑以下代码: GCC v6.1编译它,叮当声3.8拒绝它,错误如下: 2:错误:没有成员名为'foo'在'U' struct S{静态constexpr int bar=T::foo;}; 哪个编译器是对的? 会不会是因为在我们尝试在中使用它时不是一个完整的类型? 在这种情况下,它应该被认为是GCC的错误,但我想知道我是否正确之前在错误跟踪器上搜索/打开问题… 编辑 与此同时,我已经向GCC打开