【问题标题】:unique_ptr instantiation with argument that is not defined yet doesn't lead to error使用尚未定义的参数的 unique_ptr 实例化不会导致错误
【发布时间】:2018-05-11 16:46:55
【问题描述】:
#include <memory>
class Data;
std::unique_ptr<Data> p;
//class Data{}; // not working without this
int main(){}

用 g++-5 编译这段代码会出现这样的错误:

“sizeof”对不完整类型“Data”的无效应用

有人可以解释为什么如果我取消注释第 4 行编译会成功吗?据我了解,第三行编译器没有关于数据类型的完整信息。我们在这一行只有前向声明。真正的声明出现在第 4 行。

【问题讨论】:

标签: c++


【解决方案1】:

unique_ptr 类型的目标类型在模板实例化时可能不完整,但在 unique_ptr 可能尝试处置存储的指针时必须是完整的,因为这是 default_delete 的要求被调用。如果您使用的是自定义删除器,那么目标类型可能仍然不完整。

【讨论】:

  • 换句话说,在 OP 的代码中,unique_ptr 的析构函数的实例化(这似乎发生在翻译单元的末尾,因为它是一个全局变量)需要 Data完成。
  • “但必须在该点完成” 实际上在TU中,如the-point-of-instantiation-can-be-delayed-until-the-end-of-the-translation-unit
  • 好的,所以你说它必须在unique_ptr的析构函数被调用的地方完成。但在this other example 中,析构函数将在main 的末尾调用。此时class Data 仍然不完整,但这确实可以使用 g++ 5.4.1 成功编译。那么这是否会导致未定义的行为?
  • @Ruslan 正如 Jarod42 的注释中提到的实例化点可能会延迟到翻译单元的末尾。因此,您示例中的代码可能有效或导致 UB。
【解决方案2】:

你的猜测是正确的。在3rd 行编译器只知道存在这种类型。你提前声明了它。 unique_ptr 的定义方式类似于常规指针的语义。在2nd 行中,您承诺编译器在真正需要时实际定义类,并且编译器确实需要Data 类的定义来调用p 中Data 的析构函数。

sizeof 错误是在特定点“强制”完成类型定义的常用方法(在这种情况下,是为了防止 UB 对 p 析构函数中的不完整类型调用 delete)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-10-09
    • 1970-01-01
    • 1970-01-01
    • 2021-10-16
    • 2012-10-27
    • 1970-01-01
    • 2023-03-16
    • 1970-01-01
    相关资源
    最近更新 更多