C++中将指针转换为Eigen::Map<Eigen::VectorXd>对象

3

是否可以定义指向Eigen::Map对象的指针?原始代码非常复杂,但这是我想要实现的内容(伪代码)

void testfunction1(... XPtr){
  // XPtr is a pointer
  // create a vector, map it to a Map object and make XPtr point to the latter

  VectorXd Xnew(9);
  Xnew <<  10, 20, 30, 40, 50, 60, 70, 80, 90;
  Map<VectorXd> XnewMap(Xnew.data(), 9); 

  // make XPtr point to XnewMap so that Xnew data can be 
  // accessed outside testfunction1()
  // ... how? I suspect this to involve some dynamic memory allocation
};

void testfunction2(bool yes){
  // main function

  VectorXd XR(9);
  XR <<  1, 2, 3, 4, 5, 6, 7, 8, 9;
  const Map<VectorXd> X(XR.data(), 9); // yes the mapped version is needed

  // create a pointer to X, say XPtr
  // ... how?

  if(yes){ // make XPtr point to XnewMap which is defined in testfunction1()
     testfunction1(XPtr);
   };

  //... some computations

  // make XPtr point again to X
  // ... how?

};
1个回答

1

首先,在这里不需要使用指针,因为Map已经本质上是一个指针,所以更新Map对象可以更简单地使用placement new。尽管如此,您当前的设计将要求在testfunction1中进行分配,并在testfunction2中进行解除分配(如果已经分配),这并不真正安全。因此,最好采用函数式设计,将"一些计算"放入函数(或命名lambda)中,使testfunction1按值返回:

VectorXd testFunction1() { return Xnew; }

void testfunction2(bool yes){
  VectorXd XR(9);
  XR <<  1, 2, 3, 4, 5, 6, 7, 8, 9;
  const Map<VectorXd> X(XR.data(), 9);

  auto func = [&] (Eigen::Ref<VectorXd> X) {
    /* some computation */
  }

  if(yes) func(testfunction1());
  else    func(X);
};

如果您真的想保留当前的逻辑,那么这里有一个使用放置 new 的自包含示例:
#include <iostream>
#include <Eigen/Dense>
using namespace Eigen;
using namespace std;

void testfunction1(Map<VectorXd> &XMap){
  double * Xnew = new double[9];
  ::new (&XMap) Map<VectorXd>(Xnew,9);
  XMap << 10, 20, 30, 40, 50, 60, 70, 80, 90;
};

int main()
{
  bool yes = true;

  VectorXd XR(9);
  XR <<  1, 2, 3, 4, 5, 6, 7, 8, 9;
  Map<VectorXd> X(XR.data(), 9);

  if(yes) testfunction1(X);

  // use X ...
  cout << X.transpose() << endl;

  // restore X and free memory allocated in testfunction1
  if(yes){
    delete[] X.data();
    ::new (&X) Map<VectorXd>(XR.data(),9);
  }

  cout << X.transpose() << endl;
}

这很糟糕,因为如果在使用X时引发异常,它可能会泄漏。您可以通过要求testFunction1返回一个VectorXd(或任何自行处理内存分配/释放的内容)来解决手动内存管理的问题,并在主函数中执行放置new操作:

#include <iostream>
#include <Eigen/Dense>
using namespace Eigen;
using namespace std;

VectorXd testfunction1(){
  VectorXd Xnew(9);
  Xnew << 10, 20, 30, 40, 50, 60, 70, 80, 90;
  return Xnew;
};

int main()
{
  bool yes = true;

  VectorXd XR(9);
  XR <<  1, 2, 3, 4, 5, 6, 7, 8, 9;
  Map<VectorXd> X(XR.data(), 9);

  {
    VectorXd X2;
    if(yes) {
      X2 = testfunction1(); // shallow copy thanks to move semantic
      ::new (&X) Map<VectorXd>(X2.data(),9);
    }

    // use X ...
    cout << X.transpose() << endl;

    // restore X
    ::new (&X) Map<VectorXd>(XR.data(),9);
  }

  cout << X.transpose() << endl;
}

最后,如果需要将X的内容设置为只读,则应使用Map<const VectorXd>而不是像您在初始问题中所述的const Map<VectorXd>

谢谢你的回答。这就是我的当前代码所做的,但由于if else语句需要不同的函数,它使得代码难以阅读。但我会接受你的答案,因为它可能对其他人有用。然而,我仍然想知道如何声明指向Map<...>的指针。 - itQ
没有什么复杂的,只需声明typedef const MapVectorXd ConstMapVectorXd;,然后使用ConstMapVectorXd*,但是您必须处理新Map引用的数据和Map对象本身的复杂动态内存分配,这常常容易出现错误和内存泄漏。如果您使用placement new修改Map对象本身,则“仅”需要处理所引用数据的分配/释放,但这并不理想。 - ggael

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接