c++ - 返回值优化和构建结构的函数

标签 c++ c++11 move rvo

我有一个函数可以“构建”一个要返回的结构:

struct stuff {
    int a;
    double b;
    Foo c;
};
stuff generate_stuff() {
    Foo c = generate_foo();
    //do stuff to Foo, that changes Foo:
    //...
    return {1, 2.0, c};  //should this be return {1, 2.0, move(c)};?
}

我应该将 c 移出函数吗?我意识到,(N)RVO 经常可以就地构建对象,但有时情况并非如此。什么时候不能完成 (N)RVO,因此,什么时候应该 move 函数的对象?

换句话说,这显然是返回的临时对象的 RVO。问题是,c 会发生 NRVO(命名返回值优化)吗? c 是就地构造(在函数的调用点,临时 stuff 结构内),还是 c 构造在函数,然后复制到调用站点的结构中。

最佳答案

您对 move(c) 的调用并不是将 c 移出函数,而是将其移入从函数返回的临时结构中。临时返回值应始终受益于 RVO。但是,我相信 c 到临时的 move/复制不能被优化掉,因为 c 本身不是临时的。所以在这里 move 版本应该至少和复制版本一样高效(测试了 g++、clang++ 和 MVC++ 的简单场景)。

如果你必须绝对减少复制/move 操作的数量,那么你可以写

struct stuff {
    int a;
    double b;
    Foo c;
};
stuff generate_stuff() {
    stuff s{ 1, 2.0, generate_foo() };
    //use s.c instead of c
    //...
    return s;  
}

由于 NRVO,这只会导致 Foo 的单一构造,并且没有复制/move 。

编辑: 正如@dyp 在对您的问题的评论中指出的那样,Stuff 的就地构造实际上并不是 RVO 的情况,而是标准所要求的。无论如何,重要的部分是不能省略 c 的 move/复制,因此使用 move 永远不会导致性能下降。

关于c++ - 返回值优化和构建结构的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28953854/

相关文章:

c++ - 核心转储中缺少共享库负载偏移

c++ - 为什么我们在 C++ 中使用 std::function 而不是原来的 C 函数指针?

c++ - VC 2013 与 2015 中的 Lambda 删除器

jquery - 在 Jquery 中单击另一个对象时为一个对象设置动画

c++ - 我应该使用指针还是 move 语义来传递大块数据?

C++:从子对象到父对象的信息传播

c++ - g++在进行复制初始化时找不到正确的复制构造函数

c++ - 初始化一个 unique_ptr 数组

c++ - 在 Node.js 插件中阻止调用

Bash:如何将文件夹中的所有内容 move 到一个级别?