首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何确保执行RVO而不是复制?

如何确保执行RVO而不是复制?
EN

Stack Overflow用户
提问于 2020-03-05 13:16:32
回答 2查看 1.4K关注 0票数 5

在许多情况下,我希望创建一个新的数据实例,并将其返回给API调用者。

我了解到unique_ptr/shared_ptr可以用于工厂模式(例如,Factory pattern using unique_ptr in c++)

同时,我了解到在许多编译器(例如,Efficient way to return a std::vector in c++)中返回值优化(RVO)是可能的。

我更喜欢RVO,因为不用包装unique_ptr就可以更容易地使用返回的值,并且更容易阅读代码,但是,由于RVO没有得到保证,我不想意外地牺牲性能,必须使用unique_ptr来确保返回的值是moved而不是复制的。

是否有任何方法可以显式地指定要移动的返回值,这样如果RVO是可能的,它就不会抱怨什么,或者如果RVO不可能,它会触发一些编译器警告?如果这是可能的话,在这种情况下,我可以安全地摆脱返回unique_ptr。

我使用的是C++17,需要在macOS上支持AppleClang11.0,在Linux上支持g++ 9。

编辑:

我仍然在学习C++,并且在发布这个问题时没有区分RVO (返回值优化)和NRVO (称为返回值优化)。在我看来,NRVO在类似工厂方法这样的模式中更为常见和有用,例如:

代码语言:javascript
复制
vector<foo> vec;
// populate data into vec
return vec;

我正在寻找类似于return std::move_only(returned_value)的东西,如果这个值不能被移动(而不是复制到移动),它会给我一个编译器警告。也许我应该重新表述我的问题:如果NRVO没有得到保证,为什么“按值返回”仍然是这个问题(Efficient way to return a std::vector in c++)中推荐的方法,答案不应该是“它取决于”您的函数实现,以及您是否可以接受意外的性能成本?

EN

回答 2

Stack Overflow用户

发布于 2020-03-05 13:44:52

如何确保执行RVO而不是复制?

该语言已经为您从C++17开始执行此操作。

代码语言:javascript
复制
T foo() { /*stuff*/; return T{ /*stuff*/ }; }

然后,由于guaranteed copy elision,返回的对象肯定会被省略。

如果你有一个类似的构造

代码语言:javascript
复制
T foo() 
{
    T obj{ /*stuff*/ }; 
    // do stuff with obj
    return obj;
}

然后,您将得到NRVO (Nammed返回值优化),这是不可靠的,或者编译器将移动obj,因为在标准中有一条规则,如果所有具有自动存储持续时间的函数本地对象都将被移出函数之外,如果它们有一个移动构造函数。

这意味着,只有当您返回一个无法优化的对象(它是一个命名的本地参数或函数参数)时,才会得到它不支持移动的副本。全局对象总是被复制,因为它们没有作用域到函数。

票数 6
EN

Stack Overflow用户

发布于 2020-03-05 13:31:15

我更喜欢RVO,因为不用包装unique_ptr更容易使用返回的值

在不可能使用RVO、NRVO或隐式移动的情况下,您不能返回unique_ptr。它是不可复制的:

代码语言:javascript
复制
std::unique_ptr<int> ptr1;
std::unique_ptr<int> ptr2;
ptr2 = ptr1; // error: not copyable

这不编译。如果不是RVO、NRVO或move,这也不会编译:

代码语言:javascript
复制
std::unique_ptr<int> foo()
{
    return std::unique_ptr<int>{};
}

在这种情况下,这是由于C++17的保证RVO。但是即使没有RVO,你也会得到一个移动而不是一个副本。

如果不是因为NRVO或保证移动退步,这就不会编译:

代码语言:javascript
复制
std::unique_ptr<int> foo()
{
    std::unique_ptr<int> ptr;
    return ptr;
}

因此,您已经依赖于RVO,NRVO或移动。不需要unique_ptr。如果您的类型是可移动的,则可以确保即使在NRVO不可能的情况下也不会执行副本,例如并非所有return语句都返回相同的本地对象:

代码语言:javascript
复制
std::unique_ptr<int> foo(const bool flag)
{
    if (flag) {
        std::unique_ptr<int> ptr1;
        return ptr; // implicit move
    }
    std::unique_ptr<int> ptr2;
    return ptr2; // implicit move
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60546268

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档