将std :: unique_ptr <Derived>转换为std :: unique_ptr <Base>

比方说,我有工厂函数处理基类和派生类:

#include <memory> using namespace std; struct B { virtual ~B() {} }; struct D : B {}; unique_ptr<B> MakeB() { auto b = unique_ptr<B>( new B() ); return b; // Ok! } unique_ptr<B> MakeD() { auto d = unique_ptr<D>( new D() ); return d; // Doh! } 

在上面的最后一行,我需要move(d)为了使其工作,否则我得到“错误:从std::unique_ptr<D>无效转换为std::unique_ptr<D>&& 。 我的直觉说,在这种情况下,编译器应该知道它可以隐含地将一个右值赋给基指针,但是它不会。

这是不符合我的编译器(gcc 4.8.1和VS2012)? unique_ptr的预期devise? 标准中的缺陷?

编译器的行为是正确的。 当types相同时,只有一种隐含的移动,因为在编译器实际允许的情况下(见12.8 / 31和12.8 / 32),隐式移动是由编译器无法执行复制删除来指定的。

12.8 / 31(copy elision):

在具有类返回types的函数的返回语句中,当expression式是具有与函数返回types相同的cv不合格types的非易失性自动对象(函数或catch-clause参数除外) 的名称 。 ..

12.8 / 32(暗示):

当符合复制操作的标准时,首先执行重载parsing来select复制的构造函数, 就好像对象是由右值指定一样

return语句中添加了std::move调用之后,此代码在Visual Studio 2013上适用于我:

 #include <memory> using namespace std; struct B { virtual ~B() {} }; struct D : B {}; unique_ptr<B> MakeB() { auto b = unique_ptr<B>( new B() ); return std::move( b ); // *** std::move() added here! *** } unique_ptr<B> MakeD() { auto d = unique_ptr<D>( new D() ); return std::move( d ); // *** std::move() added here! *** } 

以下也有效

 unique_ptr<B> MakeB() { return unique_ptr<B>( new B() ); // *** Returning a temporary! *** } unique_ptr<B> MakeD() { return unique_ptr<D>( new D() ); // *** Returning a temporary! *** } 

当然,如果你返回std::unique_ptr<B> ,那么为什么不把D实例推到std::unique_ptr<B>中呢? 那么根本不需要转换!