返回指向前向声明类的unique_ptr是否有效?

时间:2016-03-06 11:29:42

标签: c++11 c++14 move-semantics unique-ptr

以下代码无法使用clang-700.1.81进行编译,而且是标准库:

#include <memory>

class something;

std::unique_ptr<something> external_function();

std::unique_ptr<something> local_function()
{
    auto thing = external_function();

    return thing;
}

clang的诊断:

......./include/c++/v1/memory:2626:46: note: in instantiation of member function 'std::__1::unique_ptr.....requested here
_LIBCPP_INLINE_VISIBILITY ~unique_ptr() {reset();}
                                         ^
test.cc:10:18: note: in instantiation of member function 'std::__1::unique_ptr<something, std::__1::default_delete<something> >::~unique_ptr' requested here
auto thing = external_function();
             ^
test.cc:4:7: note: forward declaration of 'something'
class something;
      ^

我猜它是在将它复制为返回值后试图销毁unique_ptr,但这是否真的有必要?无论如何它会被移动,它是否需要检查它是否可以复制,然后才意识到它更容易移动它?

我当然可以用裸指针轻松地做到这一点。 有没有其他方法允许uniqe_ptr只是“通过”翻译单元,如示例所示,不包含额外的标头来获取类的定义?

------ -------- EDIT 还尝试了GCC 5.3.0和gnu libstdc ++

不编译,也有类似的错误消息。

------ ---- EDIT

我认为它只是试图破坏原始thing对象。 感谢Rudolf的删除想法(有点乱,但只有这个选项) 查看库代码,我在unique_ptr的代码中找到了它:

        if (__tmp)
               __ptr_.second()(__tmp);

其中second(_tmp)破坏指向的对象。即使从未调用它,编译器也需要一个定义来编译它。这很愚蠢,但显然已经接受了它。

1 个答案:

答案 0 :(得分:2)

来自cppreference.com

  

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

因此,使用自定义删除器,如果完整声明可用于删除器,则可以使用前向声明的类:

#include <memory>

class Foo;

class FooDeleter
{
public:
    void operator()(Foo* pInstance);
};


std::unique_ptr<Foo, FooDeleter> pFoo;

class Foo
{
};

void FooDeleter::operator()(Foo* pInstance)
{
    delete pInstance;
}