为什么"错误:使用unique_ptr将'sizeof'无效应用于不完整类型"通过添加空析构函数来修复?

lea*_*vst 9 c++ pimpl-idiom unique-ptr c++11

我正在上课STFT.在标题中编译就好了:

class STFT; // pimpl off to prevent point name clash

class Whatever
{
private:
    STFT* stft;
Run Code Online (Sandbox Code Playgroud)

这在实施中:

#include "STFT.h"
Whatever::Whatever() : stft(new STFT()) {
// blah blah
}

Whatever::~Whatever() {
    delete stft; // pure evil
}
Run Code Online (Sandbox Code Playgroud)

但是,切换到std::unique_ptr<STFT> stft;标题中的原始指针,并删除析构函数,我得到

错误:'sizeof'无效应用于不完整类型'STFT'static_assert(sizeof(_Tp)> 0,"default_delete无法删除不完整类型");

但是,如果我只提供一个空的析构函数Whatever::~Whatever(){},那么它编译得很好.这让我完全难过.请填写我这个毫无意义的析构函数为我做的事情.

Sha*_*our 14

因此,如果我们转到std :: unique_ptr的cppreference文档:

可以为不完整类型T构造std :: unique_ptr,以便于在Pimpl习语中用作句柄.如果使用默认删除器,则必须在调用删除器的代码中完成T,这发生在析构函数,移动赋值运算符和std :: unique_ptr的重置成员函数中.(相反,std :: shared_ptr不能从原始指针构造为不完整类型,但可以在T不完整的情况下销毁).

我们可以在下面的代码中看到:

#include <memory>

class STFT; // pimpl off to prevent point name clash

class Whatever
{
    public:
     ~Whatever() ;
    private:
      std::unique_ptr<STFT> stft;
} ;

//class STFT{};

Whatever::~Whatever() {}

int main(){}
Run Code Online (Sandbox Code Playgroud)

在定义std::unique_ptr析构函数之前对定义进行定义时,不满足std::unique_ptr要求,因为这需要析构函数,T而析构函数又需要T完成.

因此,在定义时,您的实现文件似乎std::unique_ptr是完整的,std::shared_ptr否则创建默认的文件时T不会完成.


Tob*_*ght 12

我提供这种析构函数的惯用语是

Whatever::~Whatever() = default;
Run Code Online (Sandbox Code Playgroud)

重要的是它需要位于指向类型完整的地方。

  • 使用该语法会产生相同的错误。我需要明确声明一个空的 dtor。 (4认同)
  • 这取决于你把它放在哪里**。如果你把它放在头文件中,其中 `STFT` 是不完整的,那么它就像让编译器在需要的地方生成它一样糟糕。它需要在实现文件中,在`#include &lt;stft&gt;`之后,所有指向的类型都是完整的。如果它不起作用,我就不会自己使用它。 (4认同)
  • 从技术上讲,*explicitly-defaulted* 析构函数和*user-supplied* 空析构函数之间存在差异,但我现在想不出实际的区别。我发现显式的“默认”读起来更快,而且该死的费用! (3认同)
  • 这才是真正的答案。Dtor应该在编译单元中,而不是在头文件中。我花了半天时间才找到它无法编译的原因。 (2认同)