My Eigen::MatrixXf m
stores some data and I need to use this data in another array vtkFloatArray
. In order to avoid copying the data I do:
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
The problem is that the array
must live much longer than eigen matrix m
lives but when the execution goes out of the scope it seems that array
can't get values as they are removed (eigen matrix m
is deleted when out of the scope).
It seems that I can dynamically allocate eigen matrix:
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
Nevertheless SetArray() has some options to save and delete array I suspect that I will get memory leak if I use this approach. Probably std::shared_ptr<Eigen::MatrixXf> m
could help me but I'm not sure exactly as it should count references on matrix m
and vtkFloatArray
references to the m.data()
pointer (though I maybe mistaken) and I will also get memory leak.
If someone knows how to keep my eigen matrix alive while vtkFloatArray
is alive and do not get memory leak, please explain that.
Regards
My solution is based on @Peter-ReinstateMonica suggestion: create a wrapper class where both objects vtkFloatArray
and Eigen::MatrixXf
would reside and that would make possibe to control the lifetime of both these objects.
Let's call wrapper class vtkEigenFloatArray
and let it be inherited from vtkFloatArray
. As our wrapper class implicitely inherits vtkObject
we should follow vtk's inheritance structure to make it usable within vtk (for example vtkNew<vtkEigenFloatArray>
) while keeping pimp idiom (that is why you can see many vtk methods and macros within created class, this is done by analogy with vtkFloatArray
source code).
We add Eigen::MatrixXf* eigArr
member variable to our vtkEigenFloatArray
class.
We also add the method Eigen::MatrixXf* GetEigenArray()
that returns Eigen::MatrixXf* eigArr
pointer and setter void SetEigenArray(Eigen::MatrixXf* arr)
to make available to use the inner Eigen::MatrixXf
object from ouside created class.
It worth to note that vtkEigenFloatArray
and its protected Eigen::MatrixXf* eigArr
object share the same buffer. It is set every time one calls void UpdateEigenBuffer()
function. Moreover everytime when one resizes Eigen::MatrixXf* eigArr
from outside the created class the function void UpdateEigenBuffer()
must be called to update size of vtkFloatArray
-inherited class.
Also user must never externally delete Eigen::MatrixXf* eigArr
as it is deleted in vtkEigenFloatArray
's destructor.
The drawback of proposed solution:
When the main vtkEigenFloatArray
object is deleted the pointer Eigen::MatrixXf* eigArr
will not be equal to nullptr
. Thus you cannot check whether Eigen::MatrixXf* eigArr
is alive or not while you don't have holder vtkEigenFloatArray
object.
#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;
}