在函数超出范围后保留特征矩阵不被删除
Preserve Eigen matrix from deleting after the function goes out of the scope
我的 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
似乎无法获取值因为它们被移除(特征矩阵 m
在超出范围时被删除)。
看来我可以动态分配特征矩阵:
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<Eigen::MatrixXf> m
可以帮助我,但我不确定它应该计算矩阵 m
上的引用和 vtkFloatArray
对 m.data()
指针的引用(尽管我可能弄错了)和我也会内存泄漏。
如果有人知道如何在 vtkFloatArray
存活时保持我的特征矩阵存活并且不会发生内存泄漏,请解释一下。
此致
我的解决方案是基于@Peter-ReinstateMonica 的建议:创建一个包装器 class,对象 vtkFloatArray
和 Eigen::MatrixXf
都将驻留其中,这样可以控制对象的生命周期这两个对象。
让我们调用包装器 class vtkEigenFloatArray
并让它继承自 vtkFloatArray
。由于我们的包装器 class 隐式继承 vtkObject
我们应该遵循 vtk 的继承结构以使其在 vtk 中可用(例如 vtkNew<vtkEigenFloatArray>
)同时保持 pimp 习语(这就是为什么你可以看到许多 vtk 方法和创建的 class 中的宏,这是通过类比 vtkFloatArray
源代码完成的)。
我们将Eigen::MatrixXf* eigArr
成员变量添加到我们的vtkEigenFloatArray
class.
我们还添加了 Eigen::MatrixXf* GetEigenArray()
方法 returns Eigen::MatrixXf* eigArr
指针和 setter void SetEigenArray(Eigen::MatrixXf* arr)
以便可以使用内部 Eigen::MatrixXf
来自外部的对象已创建 class.
值得注意的是,vtkEigenFloatArray
及其受保护的 Eigen::MatrixXf* eigArr
对象共享同一个缓冲区。每次调用 void UpdateEigenBuffer()
函数时都会设置一次。此外,每次从创建的 class 外部调整 Eigen::MatrixXf* eigArr
的大小时,必须调用 void UpdateEigenBuffer()
函数 来更新 vtkFloatArray
-继承的大小class.
此外,用户 绝不能从外部删除 Eigen::MatrixXf* eigArr
,因为它是在 vtkEigenFloatArray
的析构函数中删除的。
建议解决方案的缺点:
删除主vtkEigenFloatArray
对象后,指针Eigen::MatrixXf* eigArr
将不等于nullptr
。因此,当你没有 holder 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;
}
我的 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
似乎无法获取值因为它们被移除(特征矩阵 m
在超出范围时被删除)。
看来我可以动态分配特征矩阵:
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<Eigen::MatrixXf> m
可以帮助我,但我不确定它应该计算矩阵 m
上的引用和 vtkFloatArray
对 m.data()
指针的引用(尽管我可能弄错了)和我也会内存泄漏。
如果有人知道如何在 vtkFloatArray
存活时保持我的特征矩阵存活并且不会发生内存泄漏,请解释一下。
此致
我的解决方案是基于@Peter-ReinstateMonica 的建议:创建一个包装器 class,对象 vtkFloatArray
和 Eigen::MatrixXf
都将驻留其中,这样可以控制对象的生命周期这两个对象。
让我们调用包装器 class vtkEigenFloatArray
并让它继承自 vtkFloatArray
。由于我们的包装器 class 隐式继承 vtkObject
我们应该遵循 vtk 的继承结构以使其在 vtk 中可用(例如 vtkNew<vtkEigenFloatArray>
)同时保持 pimp 习语(这就是为什么你可以看到许多 vtk 方法和创建的 class 中的宏,这是通过类比 vtkFloatArray
源代码完成的)。
我们将Eigen::MatrixXf* eigArr
成员变量添加到我们的vtkEigenFloatArray
class.
我们还添加了 Eigen::MatrixXf* GetEigenArray()
方法 returns Eigen::MatrixXf* eigArr
指针和 setter void SetEigenArray(Eigen::MatrixXf* arr)
以便可以使用内部 Eigen::MatrixXf
来自外部的对象已创建 class.
值得注意的是,vtkEigenFloatArray
及其受保护的 Eigen::MatrixXf* eigArr
对象共享同一个缓冲区。每次调用 void UpdateEigenBuffer()
函数时都会设置一次。此外,每次从创建的 class 外部调整 Eigen::MatrixXf* eigArr
的大小时,必须调用 void UpdateEigenBuffer()
函数 来更新 vtkFloatArray
-继承的大小class.
此外,用户 绝不能从外部删除 Eigen::MatrixXf* eigArr
,因为它是在 vtkEigenFloatArray
的析构函数中删除的。
建议解决方案的缺点:
删除主vtkEigenFloatArray
对象后,指针Eigen::MatrixXf* eigArr
将不等于nullptr
。因此,当你没有 holder 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;
}