C++ 转换std::unique_ptr<;派生>;至标准::唯一性\u ptr<;基地>;

C++ 转换std::unique_ptr<;派生>;至标准::唯一性\u ptr<;基地>;,c++,c++11,unique-ptr,c++14,C++,C++11,Unique Ptr,C++14,使用C++11,假设我有处理基类和派生类的工厂函数: #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() {

使用C++11,假设我有处理基类和派生类的工厂函数:

#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!
}
#包括
使用名称空间std;
结构B{virtual~B(){};
结构D:B{};
唯一的\u ptr MakeB()
{
自动b=唯一的(新b());
返回b;//好!
}
唯一的\u ptr MakeD()
{
自动d=唯一的(新的d());
返回d;//Doh!
}
在上面的最后一行,我需要按顺序
move(d)
,否则“错误:从
std::unique_ptr
std::unique_ptr&&
的转换无效”我的直觉告诉我,在这种情况下,编译器应该知道它可以隐式地使
d
成为右值并将其移动到基指针中,但它不会

在我的编译器(gcc 4.8.1和VS2012)中,这是一个不一致的问题吗?
unique\u ptr
的预期设计?标准中的缺陷



更新:C++14修复了这个问题。更新的编译器,如GCC 9,即使使用
-std=c++11

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! ***
}
#包括
使用名称空间std;
结构B{virtual~B(){};
结构D:B{};
唯一的\u ptr MakeB()
{
自动b=唯一的(新b());
返回std::move(b);//***std::move()已添加到此处***
}
唯一的\u ptr MakeD()
{
自动d=唯一的(新的d());
返回std::move(d);//***std::move()已添加到此处***
}
以下方法也适用

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! ***
}
unique_ptr MakeB()
{
返回唯一的_ptr(新的B());//***返回一个临时文件***
}
唯一的\u ptr MakeD()
{
返回唯一的_ptr(新的D());//***返回临时文件***
}

当然,如果您返回的是
std::unique_ptr
,那么首先为什么不将
D
实例推入
std::unique_ptr
?那就根本不需要转换了

编译器的行为是正确的。当类型相同时,只有隐式移动,因为隐式移动是根据编译器在实际允许的情况下无法执行复制省略而指定的(请参见12.8/31和12.8/32)

12.8/31(副本省略):

在具有类返回类型的函数中的return语句中,当表达式是非易失性自动对象(函数或catch子句参数除外)的名称时,与函数返回类型具有相同的cv非限定类型

12.8/32(隐式移动):

当满足省略复制操作的条件[…]时,将首先执行重载解析以选择复制的构造函数,就像对象由右值指定一样


如果类型相同,则只有隐式移动。@Simple:您有支持该声明的规范性引用吗?(如果你这样做,这将是正确的答案)@JanHudec 12.8/31和12.8/32。隐式移动是根据编译器在允许省略的情况下未能省略而指定的,当类型不同时不允许省略。这一点甚至在讨论中也有说明。真正的问题是为什么这里需要
std::move()
。对不起。完全错过了。哦,好吧。(但是,嘿,它在VS2013中仍然有效!万岁!:-P)@pepper_chico,但公认的答案是一致的@aldo接受的答案说OP编译器错误报告是正确的行为,这意味着OP的代码不符合标准。你的意思似乎是,允许无错误返回是正确的,而目前不是。现在还不清楚你是否说VS2013正在编译OP的代码,看起来你在胡说八道!因为它是@pepper_chico,所以我编辑了我的答案,以包含代码注释,强调我添加了
std::move
调用(如OP所建议的),这使代码标准兼容(这-令人惊讶!-编译时没有错误)。+1,但请注意,这已更改为C++14,并在上次会议上获得批准。谢谢,@Simple:这肯定回答了这个问题。谢谢,@JonathanWakely:这证实了我的直觉,它应该在没有
move()
的情况下工作。