return a unique_ptr 指向前向声明 class 是否有效?

Is it valid to return a unique_ptr pointing to a forward declared class?

以下代码不能用 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 复制为 return 值后销毁它,但这真的有必要吗?反正就是要搬家,是不是先看看能不能复制才知道搬家比较方便?

我当然可以用裸指针轻松做到这一点。 是否有其他方法允许 uniqe_ptr 只 "pass through" 一个翻译单元,如示例所示,而不包括额外的 header 来获得 class 的定义?

------编辑-------- 还尝试使用 GCC 5.3.0 和 gnu libstdc++

编译不正常,有类似的错误信息。

------编辑----

我认为它只是想破坏原来的thing object。 感谢 Rudolf 的删除想法(有点乱,但这是唯一的选择) 查看库代码,我在 unique_ptr 的代码中找到了这个:

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

其中 second(_tmp) 破坏指向的 object。即使它从未被调用,编译器也需要一个定义来编译它。这很愚蠢,但显然必须忍受它。

来自cppreference.com

std::unique_ptr may be constructed for an incomplete type T, such as to facilitate the use as a handle in the Pimpl idiom. If the default deleter is used, T must be complete at the point in code where the deleter is invoked, which happens in the destructor, move assignment operator, and reset member function of std::unique_ptr. (Conversely, std::shared_ptr can't be constructed from a raw pointer to incomplete type, but can be destroyed where T is incomplete).

因此,对于自定义删除器,您可以使用前向声明 class 如果完整声明可用于删除器:

#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;
}