C++ 将本地唯一\u ptr作为共享\u ptr返回

C++ 将本地唯一\u ptr作为共享\u ptr返回,c++,gcc,clang,language-lawyer,c++14,C++,Gcc,Clang,Language Lawyer,C++14,我习惯于在返回std::unique\u ptr时不使用std::move,因为这样做会禁止RVO。在这种情况下,我有一个本地std::unique\u ptr,但返回类型是std::shared\u ptr。 下面是代码示例: shared_ptr<int> getInt1() { auto i = make_unique<int>(); *i = 1; return i; } shared_ptr<int> getInt2()

我习惯于在返回std::unique\u ptr时不使用std::move,因为这样做会禁止RVO。在这种情况下,我有一个本地std::unique\u ptr,但返回类型是std::shared\u ptr。 下面是代码示例:

shared_ptr<int> getInt1() {
    auto i = make_unique<int>();

    *i = 1;

    return i;
}

shared_ptr<int> getInt2() {
    return make_unique<int>(2);
}

unique_ptr<int> getInt3() {
    auto ptr = make_unique<int>(2);

    return ptr;
}

int main() {
    cout << *getInt1() << endl << *getInt2() << *getInt3() << endl;
    return 0;
}
科里鲁的两个案例如下:

两个编译器都接受第三种情况

哪一个是错的?谢谢。

std::unique\u ptr只有在为右值时才能用于构造std::shared\u ptr。请参见以下内容的构造函数声明:

顺便说一句:我用它编译代码也失败了

source_file.cpp:14:12: error: cannot bind ‘std::unique_ptr<int, std::default_delete<int> >’ 
lvalue to ‘std::unique_ptr<int, std::default_delete<int> >&&’
     return i;
            ^

<正确答案取决于你所谈论的C++标准。< /P> 如果我们谈论的是C++11,那么clang是正确的,需要显式移动。如果我们谈论的是C++14,那么gcc是正确的,不需要显式移动

C++11在N3290/[class.copy]/p32中说:

当满足或将满足省略复制操作的条件时 met save,因为源对象是函数参数, 要复制的对象由左值重载指定 首先执行为副本选择构造函数的解析 好像对象是由右值指定的。If重载解析 失败

这要求仅当返回表达式的类型与函数返回类型相同时,才能获得隐式移动

但是改变了这一点,这个缺陷报告在C++11之后被接受,并且在C++14之前被及时接受。该段现改为:

当满足省略复制/移动操作的条件时,但是 不适用于异常声明,并且要复制的对象是 由左值指定,或者在返回语句中的表达式 是一个可能带括号的id表达式,它使用 正文中声明的自动存储持续时间或 最内层封闭函数的参数声明子句或 lambda表达式,用于选择构造函数的重载解析 首先执行复制,就好像对象是由 右值。如果第一次重载解析失败或未执行

这种修改基本上允许返回表达式类型转换为函数返回类型,并且仍然可以进行隐式移动

这是否意味着代码需要基于uucplusplus值的if/else

有人可以这样做,但我不会费心。如果我的目标是C++14,我只会:

return i;
如果代码意外地在C++11编译器下运行,则会在编译时通知您该错误,并且很容易修复:

return std::move(i);
如果您只是针对C++11,请使用移动

如果您想同时针对C++11和C++14及更高版本,请使用move。无偿使用move的缺点是可以抑制RVO返回值优化。但是,在这种情况下,RVO甚至是不合法的,因为它将返回语句转换为函数的返回类型。因此,这种无缘无故的举动不会造成任何伤害


有一次你可能会倾向于一个毫无意义的移动,即使目标是C++14,如果没有它,事情仍然在C++11中编译,并调用一个昂贵的副本转换,而不是移动转换。在这种情况下,意外地在C++11下编译会引入一个无声的性能错误。而且,在C++14下编译时,这种无缘无故的移动仍然没有有害影响。

我怀疑,当我们了解您需要它的原因时,我们将能够给出更好的答案。目前,可以通过调用make_shared而不是make_unique来解决这个问题。我想这不可能是有原因的,这将有助于理解这个原因。@Elliott:什么问题可以解决?他不是问如何解决任何问题,而是问他拥有的代码是否符合标准。您好,您能否更改您的答案,以指定移动仅适用于c++11?如果您仅使用c++11,我建议您在返回之前创建正确的类型,而不是使用return std::move。。。在你的代码中。因为编译器可能只是执行NRVO,而不是移动几次。
source_file.cpp:14:12: error: cannot bind ‘std::unique_ptr<int, std::default_delete<int> >’ 
lvalue to ‘std::unique_ptr<int, std::default_delete<int> >&&’
     return i;
            ^
return i;
return std::move(i);