繁体   English   中英

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

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

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

我了解到unique_ptr / shared_ptr可用于工厂模式(例如, 工厂模式在 c++ 中使用 unique_ptr

同时,我了解到在许多编译器中都可以进行返回值优化 (RVO)(例如, 在 c++ 中返回 std::vector 的有效方法)。

我更喜欢 RVO,因为它更容易使用返回值而不用包装unique_ptr并且更容易阅读代码,但是,由于无法保证 RVO,我不想意外牺牲性能并且必须使用unique_ptr来确保返回值是move d 而不是复制。

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

我使用的是 C++17,需要在 macOS 上支持 Apple Clang 11.0,在 Linux 上支持 g++ 9。

编辑:

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

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

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

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

从 C++17 开始,该语言已经为您做到了这一点。 如果你有一个像

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

由于保证复制省略,返回的对象保证被省略。

如果你有一个像

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

然后你会得到不保证的 NRVO(命名返回值优化),或者编译器会移动obj因为标准中有一条规则,所有具有自动存储持续时间的函数本地对象将被移出函数,如果它们有一个移动构造函数。

这意味着您将获得副本的唯一时间是您正在返回一个无法优化的对象(它是一个命名的本地对象或者它是一个函数参数)并且它不支持移动。 全局对象总是被复制,因为它们不限于函数。

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

如果 NRVO 不可能,则不能在没有 RVO、NRVO 或隐式移动的情况下返回 unique_ptr。 不可复制:

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

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

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

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

如果不是 NRVO 或保证移动回退,这将无法编译:

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

所以你已经在依赖 RVO、NRVO 或移动。 不需要 unique_ptr。 如果您的类型是可移动的,您可以确保即使在 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