How to “move” Eigen::VectorXd s

我们两清 提交于 2019-12-11 03:41:20

问题


A commenter in a recent post of mine told me I need to utilize c++11 move-semantics better to deal with a bottleneck in my code. Below is a simplified version of what needs to be fixed.

#include <iostream>
#include <Eigen/Dense>
#include <vector>

void makeCopy(std::vector<Eigen::VectorXd> &oldV){
    int n = oldV.size();
    std::vector<Eigen::VectorXd> mandatoryCopy;
    mandatoryCopy.resize(n);

    for(int i = 0; i < n; i++){
        mandatoryCopy[i] = oldV[i];
    }

    // swap the two
    oldV = mandatoryCopy;
}

int main(int argc, char **argv)
{
    // starting vector
    int len(1000);
    Eigen::VectorXd placeHolder(50);
    std::vector<Eigen::VectorXd> v(len, placeHolder);

    // copy it a bunch of times
    for(int iter = 0; iter < 1000; ++iter){
        std::cout << "iter: " << iter << "\n";
        makeCopy(v);
    }

    return 0;
}

Question: inside the for loop of makeCopy, oldV[i]is an lvalue, so how could I do something like mandatoryCopy[i]&& = oldV[i]? This is the primary bottleneck, right? I'm thinking something like mandatoryCopy[i]&& = std::move(oldV[i]), but this obviously won't compile.

Edit

As per @vsoftco's suggestion, I have tried

std::vector<Eigen::VectorXd> makeCopy2(std::vector<Eigen::VectorXd> oldV){

    int n = oldV.size();
    std::vector<Eigen::VectorXd> mandatoryCopy;
    mandatoryCopy.resize(n);

    for(int i = 0; i < n; i++){
        mandatoryCopy[i] = oldV[i];
    }
    return mandatoryCopy;
}

but I find that it is slower. Both @vsoftco and @ggael have mentioned that it would be faster to return a modified copied argument, instead of copying again, and I agree, but I doubt that this is possible for my actual code. I could ask about this later, but it would be a separate question/thread.


回答1:


You are not looking at the right line. If one copy is mandatory, then you cannot get rid of it. Nonetheless, better avoid the for loop and right:

std::vector<Eigen::VectorXd> mandatoryCopy = oldV;

On the other hand, you can omit the second copy by replacing oldV=mandatoryCopy with:

std::swap(oldV,mandatoryCopy);

that will perform a cheap pointer exchange. You get:

void makeCopy(std::vector<Eigen::VectorXd> &oldV){
  std::vector<Eigen::VectorXd> V = oldV;
  // do something with V
  std::swap(oldV,V);
}

For the functional style, in your second example, you must directly play with the argument which is already a copy:

std::vector<Eigen::VectorXd> makeCopy2(std::vector<Eigen::VectorXd> V){
  // do something with V
  return V;
}

and call it with v = makeCopy2(v);.

Do not forget to compile with -std=c++11 to get move semantic copies.

Finally, it might be better to pack your vector<VectorXd> within a MatrixXd. This will dramatically reduce the number of memory allocations:

void makeCopy3(MatrixXd &oldV){
  int n = oldV.cols();
  MatrixXd V = oldV;
  for(int i = 0; i < n; i++){
    V.col(i) *= 0.99;
  }
  oldV.swap(V); // or oldV = std::move(V); with c++11 enabled
}


来源:https://stackoverflow.com/questions/42442748/how-to-move-eigenvectorxd-s

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!