【问题标题】:Preserve Eigen matrix from deleting after the function goes out of the scope在函数超出范围后保留特征矩阵不被删除
【发布时间】:2023-04-02 11:34:01
【问题描述】:

我的Eigen::MatrixXf m 存储了一些数据,我需要在另一个数组vtkFloatArray 中使用这些数据。为了避免复制我做的数据:

vtkNew<vtkFloatArray> array;    // `vtkNew` is a smart pointer class
{
    Eigen::MatrixXf m(2, 2);
    m << 1, 2, 3, 4;
    array->SetArray(m.data(), m.size(), 1);
}
// `array` must go on living and have access to the `.data()` pointer

问题是array 的寿命必须比特征矩阵m 的寿命长得多,但是当执行超出范围时,array 似乎在被删除时无法获取值(特征矩阵@ 987654328@超出范围时被删除)。

看来我可以动态分配特征矩阵:

vtkNew<vtkFloatArray> array;
{
    Eigen::MatrixXf* m = new Eigen::MatrixXf(2, 2);
    m << 1, 2, 3, 4;
    array->SetArray(m->data(), m->size(), 1);
}
// `array` must go on living and have access to the `.data()` pointer

尽管如此SetArray() 有一些选项来保存和删除数组我怀疑如果我使用这种方法会导致内存泄漏。可能std::shared_ptr&lt;Eigen::MatrixXf&gt; m 可以帮助我,但我不确定它是否应该计算矩阵mvtkFloatArraym.data() 指针的引用(尽管我可能弄错了),我也会得到内存泄漏。

如果有人知道如何在vtkFloatArray 还活着的时候保持我的特征矩阵活着并且不会发生内存泄漏,请解释一下。

问候

【问题讨论】:

  • 术语:看来我可以将特征矩阵创建为指针 这称为动态分配。如果m 超出范围,array 也应该超出范围,所以除非vtkNew 在屏幕外玩愚蠢的游戏,否则这一点应该没有实际意义。等一下。您是否返回 array 而这就是 m 超出范围的原因?如果是这样,m 是一个动态分配技巧,肯定会导致泄漏。更糟糕的是,array 是否拥有m 的数据的所有权?那可能会繁荣!某处。
  • 我认为您正在寻找的是“我可以将支持数据缓冲区的所有权从 Matrix 转移到其他对象吗?”我不是 Eigen 大师,但沿着这些思路快速搜索一无所获。
  • 您是否需要特征矩阵?你不在你的sn-p中。如果你这样做,你可以编写一个包装器,它同时包含一个 Eigen 矩阵和一个数组,并以正确的顺序在析构函数中处理它们。
  • 您不能将Eigen::Matrix 的所有权转移到非 Eigen 对象中(不使用 Eigen 的内部结构)。以某种方式创建一个vtkArray,如果需要,可以通过Eigen::Map 访问它。
  • “为了避免复制我做的数据:” 那不行。如果要将数据存储到 vtkArray 中,则需要复制它。

标签: c++ arrays eigen vtk


【解决方案1】:

我的解决方案基于@Peter-ReinstateMonica 的建议:创建一个包装类,其中两个对象 vtkFloatArrayEigen::MatrixXf 都将驻留,这样可以控制这两个对象的生命周期。

让我们调用包装类vtkEigenFloatArray 并让它从vtkFloatArray 继承。由于我们的包装类隐式继承 vtkObject,我们应该遵循 vtk 的继承结构,使其在 vtk 中可用(例如 vtkNew&lt;vtkEigenFloatArray&gt;),同时保持 pimp 习惯用法(这就是为什么您可以在创建的类中看到许多 vtk 方法和宏,这是与vtkFloatArray源代码类推)。

我们将Eigen::MatrixXf* eigArr 成员变量添加到我们的vtkEigenFloatArray 类中。

我们还添加了返回 Eigen::MatrixXf* eigArr 指针和设置器 void SetEigenArray(Eigen::MatrixXf* arr) 的方法 Eigen::MatrixXf* GetEigenArray() 以使用外部创建的类中的内部 Eigen::MatrixXf 对象。

值得注意的是vtkEigenFloatArray 及其受保护的Eigen::MatrixXf* eigArr 对象共享同一个缓冲区。每次调用void UpdateEigenBuffer() 函数时设置。此外,每当从创建的类外部调整Eigen::MatrixXf* eigArr 的大小时,必须调用函数void UpdateEigenBuffer() 来更新vtkFloatArray-inherited 类的大小。

此外,用户绝不能从外部删除Eigen::MatrixXf* eigArr,因为它在vtkEigenFloatArray 的析构函数中被删除。

建议解决方案的缺点:

当主vtkEigenFloatArray 对象被删除时,指针Eigen::MatrixXf* eigArr 将不等于nullptr。因此,当您没有持有者 vtkEigenFloatArray 对象时,您无法检查 Eigen::MatrixXf* eigArr 是否存在。

#include <vtkNew.h>
#include <vtkFloatArray.h>
#include <Eigen/Dense>
#include <iostream>

class vtkEigenFloatArray : public vtkFloatArray
{
public:
  static vtkEigenFloatArray* New();
  vtkTypeMacro(vtkEigenFloatArray, vtkFloatArray);


  void PrintSelf(ostream& os, vtkIndent indent) override
  {
    this->RealSuperclass::PrintSelf(os, indent);
  }

  // This macro expands to the set of method declarations that
  // make up the interface of vtkAOSDataArrayTemplate, which is ignored
  // by the wrappers.
#if defined(__VTK_WRAP__) || defined(__WRAP_GCCXML__)
  vtkCreateWrappedArrayInterface(float);
#endif

  /**
   * A faster alternative to SafeDownCast for downcasting vtkAbstractArrays.
   */
  static vtkEigenFloatArray* FastDownCast(vtkAbstractArray* source)
  {
    return static_cast<vtkEigenFloatArray*>(Superclass::FastDownCast(source));
  }

  /**
   * Get the minimum data value in its native type.
   */
  static float GetDataTypeValueMin() { return VTK_FLOAT_MIN; }

  /**
   * Get the maximum data value in its native type.
   */
  static float GetDataTypeValueMax() { return VTK_FLOAT_MAX; }
  
  /**
   * Deletes previous pointer and sets new
   */
  void SetEigenArray(Eigen::MatrixXf* arr)
  {
    delete eigArr;
    eigArr = arr;
    UpdateEigenBuffer();
  }

  /**
   * Don't delete this pointer!
   */
  Eigen::MatrixXf* GetEigenArray()
  {
    return eigArr;
  }

  /**
   * Must be manually called every time Eigen::MatrixXf resized
   */
  void UpdateEigenBuffer()
  {
    this->SetArray(eigArr->data(), eigArr->size(), 1); // must be set to 1 or in destructor runtime error
  }

protected:
  vtkEigenFloatArray()
  {
    eigArr = new Eigen::MatrixXf();
  }

  ~vtkEigenFloatArray() override
  {
    delete eigArr;
    eigArr = nullptr;
  }
  
  Eigen::MatrixXf* eigArr;

private:
  typedef vtkAOSDataArrayTemplate<float> RealSuperclass;

  vtkEigenFloatArray(const vtkEigenFloatArray&) = delete;
  void operator=(const vtkEigenFloatArray&) = delete;

  friend class vtkNew<vtkEigenFloatArray>;
};

vtkStandardNewMacro(vtkEigenFloatArray);


int main(int argc, char *argv[]) {
  /* General usage */
  vtkNew<vtkEigenFloatArray> arr;
  Eigen::MatrixXf* M = arr->GetEigenArray();
  M->resize(2, 2);
  *M << 1, 2, 3, 4;
  arr->UpdateEigenBuffer();

  std::cout << "Eigen M:" << std::endl;
  std::cout << *M << std::endl;

  std::cout << "VTK array:" << std::endl;
  for(int i = 0; i < arr->GetSize(); i++)
    std::cout << arr->GetValue(i) << std::endl;

  arr->Allocate(5);
  std::cout << "Eigen M:" << std::endl;
  std::cout << *M << std::endl;

  std::cout << "VTK array:" << std::endl;
  for(int i = 0; i < arr->GetSize(); i++)
    std::cout << arr->GetValue(i) << std::endl;

  /* Test `SetEigenArray` */
  Eigen::MatrixXf* MM = new Eigen::MatrixXf();
  MM->resize(2,2);
  *MM << 11, 22, 33, 44;

  arr->SetEigenArray(MM);

  std::cout << "Eigen MM:" << std::endl;
  std::cout << *MM << std::endl;

  std::cout << "VTK array:" << std::endl;
  for(int i = 0; i < arr->GetSize(); i++)
    std::cout << arr->GetValue(i) << std::endl;

  return 0;
}

【讨论】:

  • 请在您的回答中提供更多详细信息。正如目前所写的那样,很难理解您的解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-29
  • 2014-08-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-10
相关资源
最近更新 更多