用于 pimpl 的 Unique_ptr 用法 - 即使声明了析构函数也不会编译

亚萨

我正在尝试将 unique_ptr 用于 pimpl 成语。所以我在类中声明了一个析构函数,所以在没有定义 impl 类的地方不会实例化 unique_ptr 删除,然后我在另一个文件中定义它。

这是我的布局:

包装器.h:

#pragma once
#include <memory>

struct Wrapper
{
    class Impl;
    ~Wrapper();
    std::unique_ptr<Impl> _impl;
};

包装器.cpp:

#include "wrapper.h"

class Wrapper::Impl {};
Wrapper::~Wrapper() = default;

这个文件编译得很好。但是,在编译 main.cpp 时,我收到了不完整的类型错误(请参阅下面的错误):

主.cpp:

#include "wrapper.h"

int main()
{
    Wrapper w;
    return 0;
}

但是,如果我在 main.cpp 的末尾添加 wrapper.cpp 中的两行,它编译得很好。我不明白两件事:

  1. 为什么首先会发生错误?我想在类中声明析构函数移动删除调用点?
  2. 为什么在 main.cpp 文件末尾添加代码会影响此错误?我虽然“如果使用默认删除器,则 T 必须调用删除器的代码点完成,这发生在析构函数中”(来自cppreference)。

我错过了什么?

更新:

按照@AdrianMole 的建议,我在类 Wrapper 定义中添加了一个 ctor 声明,并且由于某种原因它修复了错误,即使错误(和 unique_ptr 规范)指的是析构函数。

更新了 wrapper.h:

struct Wrapper
{
    class Impl;
    Wrapper();
    ~Wrapper();
    std::unique_ptr<Impl> _impl;
};

所以我补充一个问题:

  1. 为什么添加构造函数声明可以解决这个问题?

这些是我使用 MSVC 遇到的错误,但类似的错误发生在 clang 或 gcc(我尝试过在线编译器):

内存(2536,1):错误 C2027:使用未定义的类型“Wrapper::Impl”

wrapper.h(7): message : 见'Wrapper::Impl'的声明

内存(2535):消息:编译类模板成员函数时'void std::default_deleteWrapper::Impl::operator ()(_Ty *) noexcept const'

    with

    [

        _Ty=Wrapper::Impl

    ]

内存(2647):消息:请参阅对正在编译的函数模板实例化“void std::default_deleteWrapper::Impl::operator ()(_Ty *) noexcept const”的引用

    with

    [

        _Ty=Wrapper::Impl

    ]

内存(2574):消息:请参阅对正在编译的类模板实例化“std::default_deleteWrapper::Impl”的引用

wrapper.h(9):消息:请参阅对正在编译的类模板实例化 'std::unique_ptrWrapper::Impl,std::default_delete<Wrapper::Impl>' 的引用

内存(2536,25):错误 C2338:无法删除不完整的类型

内存(2537,1):警告 C4150:删除指向不完整类型“Wrapper::Impl”的指针;没有调用析构函数

wrapper.h(7): message : 见'Wrapper::Impl'的声明

阿特尔

任何构造函数定义(包括隐式定义的默认构造函数)都可能调用类类型的所有成员对象的类型的析构函数。这样做的基本原理是,如果构造后面的成员抛出异常,则需要调用所有先前成员的析构函数。对于最后一个成员,这不是严格要求的,但标准没有例外。

例如,如果您的课程是:

struct complete_type_with_throwing_constructor {
    complete_type_with_throwing_constructor() { throw 0; }
};

struct Wrapper
{
    class Impl;
    ~Wrapper();
    std::unique_ptr<Impl> _impl;
    complete_type_with_throwing_constructor x;
};

然后隐式默认构造函数Wrapperwill 构造_impl然后在xthrows的默认构造函数之后销毁它

如果您显式声明默认构造函数,这就是您的代码工作的原因。这将定义移动到std::unique_ptr<Impl>可以实例化的析构函数的点


至于你的第二个问题,你是对的,之后添加定义时代码仍然不能工作。只是编译器没有检测到它,所以他们没有错误。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

unique_ptr编译错误

static_pointer_cast的替代方案,用于unique_ptr

unique_ptr :: release()是否调用析构函数?

从函数返回unique_ptr

使用PIMPL习惯用法为可复制的类编写可复制的unique_ptr

unique_ptr,pimpl / forward声明和完整定义

使用std :: unique_ptr的C ++ Pimpl成语不完整类型

dll中的std :: unique_ptr pimpl用Visual Studio生成C4251

unique_ptr pimpl和不完整类型

这是unique_ptr的正确用法吗?

当析构函数在类主体中声明为unique_ptr作为同一类的成员时发生编译器错误

使用shared_ptr的Pimpl习惯用法处理不完整类型

在向量的声明中移动unique_ptr

Pimpl with unique_ptr:为什么我必须将接口的构造函数定义移至“ .cpp”?

C ++ / Pimpl:原始指针还是unique_ptr?有什么更好的选择?

用于unique_ptr向量的解引用包装器?

没有合适的默认构造函数可用于std :: unique_ptr

std :: unique_ptr析构函数构造函数顺序

PIMPL习惯用法,用于指向C ++中的类的指针

使用unique_ptr保护的析构函数

使用std :: map时,包含unique_ptr的结构中的默认析构函数会导致编译错误

std :: unique_ptr构造函数的行为

使用已删除的函数unique_ptr

在声明为返回unique_ptr <Base>的函数中返回unique_ptr <Derived>

删除函数unique_ptr

unique_ptr析构函数的优势

std :: unique_ptr constexpr构造函数

模板实例化和带有 unique_ptr 的 pimpl 习惯用法

unique_ptr 两次调用析构函数