将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>
中呢? 那么根本不需要转换!