首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >“类型为'A‘的临时函数具有受保护的析构函数”,但其类型为B

“类型为'A‘的临时函数具有受保护的析构函数”,但其类型为B
EN

Stack Overflow用户
提问于 2019-06-25 08:16:13
回答 1查看 6.1K关注 0票数 11

在使用Clang 8.0.0+和-std=c++17编译的以下代码中,使用B{}创建派生类实例会产生错误error: temporary of type 'A' has protected destructor。当临时的类型为B (因此应该有一个公共析构函数)时,为什么A会出现在此消息中?

https://godbolt.org/z/uOzwYa

代码语言:javascript
复制
class A {
protected:
    A() = default;
    ~A() = default;
};

class B : public A {
// can also omit these 3 lines with the same result
public:
    B() = default;
    ~B() = default;
};

void foo(const B&) {}

int main() {

    // error: temporary of type 'A' has protected destructor
    foo(B{});
    //    ^

    return 0;
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-06-25 08:44:43

这是C++20之前的aggregate initialization的一个微妙问题。

在C++20之前,B (和A)是aggregate types

(强调我的)

没有用户提供的、继承的或显式的构造函数(显式默认或删除的构造函数被允许)(从C++17开始)(直到C++20)

然后

如果初始化器子句的数目小于成员数目and bases (since C++17)或者初始化器列表完全为空,则按照通常的列表初始化规则(对于非类类型和使用默认构造函数的非聚合类执行值初始化,对于聚合体执行聚合初始化),剩余的成员and bases (since C++17)通过空列表进行by their default member initializers, if provided in the class definition, and otherwise (since C++14)初始化。

因此,B{}通过聚合初始化来构造一个临时对象,它将直接用空表初始化基对象,即进行聚合初始化来构造A基子对象。请注意,绕过了B的构造函数。问题是在这样的上下文中,不能调用protected描述器来销毁直接构造的A类型的基子对象。(它不会抱怨protected构造函数,因为A的聚合初始化也绕过了它。)

您可以将其更改为foo(B());以避免聚合初始化;B()执行value-initialization,临时对象将由B的构造函数初始化,然后一切正常。

顺便说一句,既然使用了C++20,你的代码就会工作得很好。

没有用户声明或继承的构造函数(从C++20开始)

B (和A)不再是聚合类型。B{}先执行list initialization,然后用B的构造函数初始化临时对象,效果和B()一样。

票数 13
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56745324

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档