QScopedPointer,boost :: scoped_ptr - 为什么抱怨不完整的类型?

vla*_*sch 5 c c++ boost smart-pointers qt4

我有c-Structure,我想嵌入一个cpp类而不会中毒我的全局命名空间,所以我不想包含c-header.

这就是为什么我想使用带有前向声明结构名称的智能范围指针(QScopedPointerboost::scoped_ptr).

我不明白的是在编译时失败的两个提到的作用域指针的实现:

促进:

错误C2027:使用未定义类型'xxx'

template<class T> inline void checked_delete(T * x)
{
    // intentionally complex - simplification causes regressions
    typedef char type_must_be_complete[ sizeof(T)? 1: -1 ]; // < here
    (void) sizeof(type_must_be_complete);
    delete x;
}
Run Code Online (Sandbox Code Playgroud)

在Qt中也是如此:

错误C2027:使用未定义类型'xxx'

template <typename T>
struct QScopedPointerDeleter
{
    static inline void cleanup(T *pointer)
    {
        // Enforce a complete type.
        // If you get a compile error here, read the section on forward declared
        // classes in the QScopedPointer documentation.
        typedef char IsIncompleteType[ sizeof(T) ? 1 : -1 ]; // < here
        (void) sizeof(IsIncompleteType);

        delete pointer;
    }
};
Run Code Online (Sandbox Code Playgroud)

引用的文档没有帮助我.它表示前向声明的类的析构函数不必是内联的,并且必须在每个可能的范围内清除指定指针时都可用.但我的c结构没有析构函数.

所以我有两个问题:

  1. 为什么这个检查呢?因为知道调用delete的大小似乎无关紧要.
  2. 怎么处理这个?

Mic*_*iak 9

  1. 必须在智能指针被破坏的地方知道保存在智能指针中的对象类型,因此可以调用保留对象的正确析构函数
  2. 你的类(持有智能指针的那个)有析构函数吗?如果不是 - 在cpp文件中添加一个.否则,编译器会在看到您的类定义时尝试添加一个,但由于智能指针的析构函数尝试访问未知类型,因此无法执行此操作.


ikh*_*ikh 6

我的c-Structure没有析构函数.

一方面,.你的struct实际上有一个析构函数 - 隐式声明的析构函数.


无论如何,让我们继续吧.

delete pointer;
Run Code Online (Sandbox Code Playgroud)

在编译这段代码时,我们应该调用析构函数*pointer.但是,如果*pointer是不完整类型,我们无法知道要调用的析构函数.在这种情况下,标准[expr.delete]表示它会导致未定义的行为.

如果被删除的对象在删除时具有不完整的类类型,并且完整的类具有非平凡的析构函数或释放函数,则行为是未定义的.

如您所见,如果您的结构没有非平凡的析构函数或释放函数(特定于类operator delete),则它不是UB.但是,您可能可以在结构中添加析构函数 - 您这样做.如果你没有解决这一点,它就变成了错误的bug.(编译器不必报告它;它只是UB,而不是非法代码.)所以它被认为是一种好的做法.

因此,删除不完整的类型确实是我们应该避免的.为避免这种情况,我们使用了这个技巧.

typedef char type_must_be_complete[ sizeof(T)? 1: -1 ]; // < here
(void) sizeof(type_must_be_complete);
Run Code Online (Sandbox Code Playgroud)

因为sizeof(T)非法代码T是不完整类型,所以它可以减少编译时错误,因为UB导致程序疯狂.

尽管补偿速度较慢,我强烈建议您尽量包括它; 虽然你的结构很简单但没有operator delete,但是可以在不修复的情况下添加它们,这会导致UB.