简体   繁体   English

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

[英]How can I ensure RVO instead of copy is performed?

In many cases, I would like to create a new instance of data and return it to the API caller.在许多情况下,我想创建一个新的数据实例并将其返回给 API 调用方。

I learned that unique_ptr / shared_ptr can be used for factory pattern (for example, Factory pattern using unique_ptr in c++ )我了解到unique_ptr / shared_ptr可用于工厂模式(例如, 工厂模式在 c++ 中使用 unique_ptr

At the same time, I learned that returned value optimization (RVO) is possible in many compilers (for example, Efficient way to return a std::vector in c++ ).同时,我了解到在许多编译器中都可以进行返回值优化 (RVO)(例如, 在 c++ 中返回 std::vector 的有效方法)。

I prefer RVO since it is easier to use the returned value without a wrapping unique_ptr and easier to read the code, however, since the RVO is not guaranteed, I don't want to sacrifice performance unexpectedly and have to use unique_ptr to ensure returned value is move d instead of copied.我更喜欢 RVO,因为它更容易使用返回值而不用包装unique_ptr并且更容易阅读代码,但是,由于无法保证 RVO,我不想意外牺牲性能并且必须使用unique_ptr来确保返回值是move d 而不是复制。

Is there any approach that I can explicitly specify the return value to be moved, so that either it will not complain anything if RVO is possible or it will trigger some compiler warning if RVO is not possible?是否有任何方法可以明确指定要移动的返回值,以便在 RVO 可能的情况下它不会抱怨任何内容,或者如果 RVO 不可能,它将触发一些编译器警告? If this is possible, I can safely get rid of returning a unique_ptr in this case.如果这是可能的,我可以安全地摆脱在这种情况下返回 unique_ptr 的情况。

I am using C++17 and need to support Apple Clang 11.0 on macOS and g++ 9 on Linux.我使用的是 C++17,需要在 macOS 上支持 Apple Clang 11.0,在 Linux 上支持 g++ 9。

Edited:编辑:

I am still learning C++ and didn't make distinction between RVO (Return Value Optimization) and NRVO (Named Return Value Optimization) when posting this question.我仍在学习 C++ 并且在发布此问题时没有区分 RVO(返回值优化)和 NRVO(命名返回值优化)。 It seems to me NRVO is more common and useful in patterns like factory method, for example:在我看来 NRVO 在像工厂方法这样的模式中更常见和有用,例如:

vector<foo> vec;
// populate data into vec
return vec;

And I am looking for something like a return std::move_only(returned_value) that will give me a compiler warning if this value cannot be moved (not copy to move).我正在寻找类似return std::move_only(returned_value) ,如果这个值不能移动(不是复制移动),它会给我一个编译器警告。 Maybe I should re-phrase my question as: if NRVO is not guaranteed, why "return by value" is still the recommended way in this question ( Efficient way to return a std::vector in c++ ), shouldn't the answer be "it depends" on your function implementation and whether or not you could accept unexpected performance cost?也许我应该重新表述我的问题:如果不能保证 NRVO,为什么“按值返回”仍然是这个问题中的推荐方式( 在 c++ 中返回 std::vector 的有效方法),答案不应该是“这取决于”您的功能实现以及您是否可以接受意外的性能成本?

How can I ensure RVO instead of copy is performed?如何确保执行 RVO 而不是复制?

The language does this already for you starting in C++17.从 C++17 开始,该语言已经为您做到了这一点。 If you have a construct like如果你有一个像

T foo() { /*stuff*/; return T{ /*stuff*/ }; }

Then the returned object is guaranteed to be elided thanks to guaranteed copy elision .由于保证复制省略,返回的对象保证被省略。

If you have a construct like如果你有一个像

T foo() 
{
    T obj{ /*stuff*/ }; 
    // do stuff with obj
    return obj;
}

Then you will either get NRVO (Nammed Return Value Optimization) which is not guranteed, or the compiler will move obj because there is a rule in the standard that all function local objects with automatic storage duration will be moved out of the function if they have a move constructor.然后你会得到不保证的 NRVO(命名返回值优化),或者编译器会移动obj因为标准中有一条规则,所有具有自动存储持续时间的函数本地对象将被移出函数,如果它们有一个移动构造函数。

That means the only time you'll get a copy is if you are returning an object that can't be optimized (it is a named local or it's a function parameter) and it doesn't support moving.这意味着您将获得副本的唯一时间是您正在返回一个无法优化的对象(它是一个命名的本地对象或者它是一个函数参数)并且它不支持移动。 Global objects are always copied as they are not scoped to the function.全局对象总是被复制,因为它们不限于函数。

I prefer RVO since it is easier to use the returned value without a wrapping unique_ptr我更喜欢 RVO 因为它更容易使用返回值而不用包装 unique_ptr

You cannot return a unique_ptr without either RVO, NRVO, or implicit move in case NRVO isn't possible.如果 NRVO 不可能,则不能在没有 RVO、NRVO 或隐式移动的情况下返回 unique_ptr。 It's not copyable:不可复制:

std::unique_ptr<int> ptr1;
std::unique_ptr<int> ptr2;
ptr2 = ptr1; // error: not copyable

This does not compile.这不编译。 If it weren't for RVO, NRVO or move, this wouldn't compile either:如果不是 RVO、NRVO 或 move,这也不会编译:

std::unique_ptr<int> foo()
{
    return std::unique_ptr<int>{};
}

In this case, this is due to C++17's guaranteed RVO.在这种情况下,这是由于 C++17 的保证 RVO。 But even if there was no RVO, you'd still get a move instead of a copy.但即使没有 RVO,你仍然会得到一个移动而不是一个副本。

And if it weren't for NRVO or guaranteed move fallback, this wouldn't compile:如果不是 NRVO 或保证移动回退,这将无法编译:

std::unique_ptr<int> foo()
{
    std::unique_ptr<int> ptr;
    return ptr;
}

So you are already depending on RVO, NRVO or moves.所以你已经在依赖 RVO、NRVO 或移动。 No need for unique_ptr.不需要 unique_ptr。 If your types are movable, you can be sure no copies are performed even in cases where NRVO isn't possible, like when not all return statements return the same local object:如果您的类型是可移动的,您可以确保即使在 NRVO 不可能的情况下也不会执行任何副本,例如并非所有return语句都返回相同的本地对象:

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
}

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

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