如何"move"特征::VectorXd s

How to "move" Eigen::VectorXd s

本文关键字:VectorXd 特征 move 如何      更新时间:2023-10-16

我最近的一篇文章中的评论者告诉我,我需要更好地利用C 11 Move-Semantics来处理我的代码中的瓶颈。以下是需要修复的简化版本。

#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;
}

问题:makeCopy的for循环内部,oldV[i]是一个LVALUE,那么我该怎么做mandatoryCopy[i]&& = oldV[i]之类的事情?这是主要的瓶颈,对吗?我在想类似mandatoryCopy[i]&& = std::move(oldV[i])的东西,但这显然不会编译。

编辑

根据 @vsoftco的建议,我尝试了

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;
}

,但我发现它较慢。@vsoftco和@ggael都提到,返回修改后的复制参数,而不是再次复制,我同意,但我怀疑我的实际代码是否有可能。我稍后可以问一下,但这将是一个单独的问题/线程。

您没有查看正确的行。如果一个副本是强制性的,那么您将无法摆脱它。尽管如此,最好避免循环和正确的循环:

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

另一方面,您可以通过以下方式替换oldV=mandatoryCopy来省略第二份副本。

std::swap(oldV,mandatoryCopy);

将执行廉价的指针交换。你得到:

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

对于功能样式,在您的第二个示例中,您必须直接使用已经是副本的参数:

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

并使用v = makeCopy2(v);

不要忘记使用-std=c++11编译以获取移动语义副本。

最后,最好将vector<VectorXd>包装在MatrixXd中。这将急剧减少内存分配的数量:

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
}