简体   繁体   English

将std :: unique_ptr返回给多态类对象的正确方法

[英]The correct way of returning std::unique_ptr to an object of polymorphic class

Let's say I have the following hierarchy of classes: 假设我有以下类的层次结构:

struct Base 
{
};

struct Derived : public Base 
{ 
    void DoStuffSpecificToDerivedClass() 
    {
    } 
};

And the following factory method: 以下工厂方法:

std::unique_ptr<Base> factoryMethod()
{
    auto derived = std::make_unique<Derived>();
    derived->DoStuffSpecificToDerivedClass();
    return derived; // does not compile
}

The problem is, the return statement does not compile, because std::unique_ptr does not have a copy constructor with covariance support (which makes sense since it does not have any copy constructors), it only has a move constructor with covariance support. 问题是, return语句没有编译,因为std::unique_ptr没有具有协方差支持的复制构造函数(这是有意义的,因为它没有任何复制构造函数),它只有一个具有协方差支持的移动构造函数。

What is the best way to make solve this problem? 解决这个问题的最佳方法是什么? I can think of two ways: 我可以想到两种方式:

return std::move(derived); // this compiles
return std::unique_ptr<Base>(derived.release()); // and this compiles too

EDIT 1: I'm using Visual C++ 2013 as my compiler. 编辑1:我使用Visual C ++ 2013作为我的编译器。 The original error message for return derived looks like this: return derived的原始错误消息如下所示:

Error   1   error C2664: 'std::unique_ptr<Base,std::default_delete<_Ty>>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)' : cannot convert argument 1 from 'std::unique_ptr<Derived,std::default_delete<Derived>>' to 'std::unique_ptr<Derived,std::default_delete<Derived>> &&'

EDIT 2: It is a freshly created console app from a standard VS 2013 template. 编辑2:它是标准VS 2013模板中新创建的控制台应用程序。 I haven't tweaked any compiler settings. 我没有调整任何编译器设置。 Compiler command line looks like this: 编译器命令行如下所示:

Debug: 调试:

/Yu"stdafx.h" /GS /analyze- /W3 /Zc:wchar_t /ZI /Gm /Od /sdl /Fd"Debug\vc120.pdb" /fp:precise /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_LIB" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /Oy- /MDd /Fa"Debug\" /EHsc /nologo /Fo"Debug\" /Fp"Debug\CppApplication1.pch" 

Release: 发布:

/Yu"stdafx.h" /GS /GL /analyze- /W3 /Gy /Zc:wchar_t /Zi /Gm- /O2 /sdl /Fd"Release\vc120.pdb" /fp:precise /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_LIB" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /Gd /Oy- /Oi /MD /Fa"Release\" /EHsc /nologo /Fo"Release\" /Fp"Release\CppApplication1.pch" 

You can do this: 你可以这样做:

return std::move(derived);

That way you tell the compiler no copy is needed, which satisfies the requirements of unique_ptr . 这样你告诉编译器不需要复制,这满足了unique_ptr的要求。 If the types matched perfectly you should not need to explicitly specify move , but in this case you do. 如果类型匹配完美,则不需要明确指定move ,但在这种情况下,您可以。

As stated in the question, the problem is, the return statement does not compile, std::unique_ptr does not have a copy constructor with covariance support, it only has a move constructor with covariance support, however, compiler still doesn't move from std::unique_ptr<Derived> . 正如问题中所述,问题是,return语句没有编译, std::unique_ptr没有带协方差支持的复制构造函数,它只有一个带协方差支持的移动构造函数,但编译器仍然没有从std::unique_ptr<Derived>

It is because conditions for moving from an object returned from a function are tied closely to the criteria for copy elision, which strictly requires that type of the object being returned need to be same as the return type of the function. 这是因为从函数返回的对象移动的条件与复制省略的标准紧密相关,这严格要求返回的对象的类型需要与函数的返回类型相同。

[class.copy]/32: [class.copy] / 32:

When the criteria for elision of a copy operation are met or would be met save for the fact that the source object is a function parameter, and the object to be copied is designated by an lvalue, overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue. 当满足或将满足复制操作的省略标准时,除了源对象是函数参数这一事实,并且要复制的对象由左值指定,重载决策选择复制的构造函数是首先执行,好像对象是由右值指定的。

Therefore, I prefer, 因此,我更喜欢,

return std::move(derived);

However, there is rule change in DR-9R5 so that the return value will be treated as an rvalue even when the types are not the same, gcc-5 implemented the rule and you don't need to change your code for gcc-5 as shown here . 但是, DR-9R5中存在规则更改,因此即使类型不同,返回值也将被视为右值,gcc-5实现了规则,您无需更改gcc-5的代码如图所示这里

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM