首页 > 解决方案 > 诱导编译器避免/触发右值上的副本

问题描述

在下面的代码中,我有一个函数foo以 a 作为参数,std::function返回一个大对象(这里是 a vector)并仅使用它来访问它的值。大对象可以作为主显示中的两个 lambda 表达式即时构建fun或作为对现有对象的引用。

我想通过选择正确的返回类型来优化此代码以避免无用的副本std::function

如果我使用按值返回,RVO 会优化副本并为“即时构建”情况制作我想要的内容:没有完成副本,向量准确地构建在它需要的位置,然后在最后销毁的foo。但是,在第二种情况下,即使我真的不需要它,编译器也会复制向量。第二种情况是按引用返回的完美情况,但这会破坏第一种情况,因为对临时的引用是邪恶的。

我知道foo直接引用向量可以解决这种特殊情况下的问题,但我的用例更复杂。有没有办法解决这个问题?

#include <vector>
#include <iostream>
#include <functional>

struct myVec : public std::vector<double> {
    using std::vector<double>::vector;
    myVec(myVec const & v){
        std::cout << "Copy ctor\n";
        *this=v;
    }
};


void foo(std::function<myVec(void)> fun){
    for(auto & v : fun()){
        std::cout << v << " ";
    }
    std::cout<<std::endl;
}

int main() {
    foo([]()->myVec{return myVec(100,0.);});
    myVec existing(100,1.);
    foo([&existing]()->myVec{return existing;});
    return 0;
}

标签: c++optimizationcopy

解决方案


[&existing]()->myVec{return existing;}通过副本返回,而不是通过引用返回,因此它会创建副本。

你需要这样[&existing]()->myVec&{return existing;}

然后问题是std::function

所以要么提供2个重载(void foo(std::function<myVec()>)void foo(std::function<myVec&()>)),要么使用模板并摆脱std::function:

template <typename F>
void foo(F fun){
    for (const auto & v : fun()){
        std::cout << v << " ";
    }
    std::cout<<std::endl;
}

推荐阅读