I have a question regarding proper use of vtkSmartPointer as a member variable. As I understand it, to prevent the smart pointer from going out of scope, it can be set as a member variable so that it is not deleted until the class object is deleted. As in my example below, accessing the smart pointer in class A is not a problem. However, in class B trying to explicitly access the smart pointer leads to segfaults unless I specifically run the class A method from class B ( see getSomethingFromA()).
Why doesn’t a->getSomething() work?
class A
{
A()
{
doSomething();
}
void doSomething()
{ // read from file and copy to poly data
// ...
sp->ShallowCopy(reader->GetOutput());
// everything with sp is ok here .. reference count = 1
sp->PrintSelf(std::cout, vtkIndent(2));
}
vtkSmartPointer<vtkObject> getSomething()
{
return this->sp;
}
vtkSmartPointer<vtkPolyData> sp = vtkSmartPointer<vtkPolyData>::New();
}
class B
{
B()
{
a = new A;
};
void getSomethingFromA()
{
a->sp = a->doSomething(); // this works to create a new reference
a->sp->PrintSelf(std::cout, vtkIndent(2)); // prints ref count = 2
vtkSmartPointer<vtkPolyData> spB = vtkSmartPointer<vtkPolyData>::New();
spB = a->getSomething(); // this does not work, and segfaults.
}
A *a;
}
This looks very odd and I’m surprised it even compiles. That implicit cast from a vtkSmartPointer<vtkObject> into a vtkSmartPointer<vtkPolyData> looks fishy.
I tried to reproduce this issue with the following reduced test:
#include "vtkFloatArray.h"
#include "vtkSmartPointer.h"
struct A
{
A() { }
vtkSmartPointer<vtkObject> getSomething() { return this->sp; }
vtkSmartPointer<vtkFloatArray> sp = vtkSmartPointer<vtkFloatArray>::New();
};
int main(int, char*[])
{
A a;
vtkSmartPointer<vtkFloatArray> spB = vtkSmartPointer<vtkFloatArray>::New();
spB = a.getSomething(); // this does not work, and segfaults.
return 0;
}
As I expected the line spB = a.getSomething(); doesn’t compile on my machine as up the inheritance tree is not allowed ( as seen below ). This happens as vtkObject isn’t a subclass of vtkFloatArray. What you want to do is spB = vtkFloatArray::SafeDownCast(a.getSomething());.
... required from ‘vtkSmartPointer<ArrayType>& vtkSmartPointer<ArrayType>::operator=(const vtkSmartPointer<U>&) [with U = vtkObject; T = vtkFloatArray]’
error: static assertion failed: Argument type is not compatible with vtkSmartPointer<T>'s T type.
(you created a new polydata but in the next line you reassigning the only smartpointer that referenced it, which deleted the polydata)
Another inefficiency is to use vtkSmartPointer to return the pointer from class A. You could return a simple pointer, as the ownership of the polydata is clear (it is being owned by object of class A, nothing will delete it while the other class is using it).
Ownership would be even clearer by returning vtkPolyData& (or even vtkPolyData const&!), but VTK is in very backwards in that respect, so normal C++ reference idioms just don’t work in its codebase.
Thanks for the replies and insight everyone. With the full example below I was able to access the smart pointer as expected. Boiling it down to this example helped, and I was able to expand upon it my code. The original issue was just a messy implementation, and not cleaning out all the project headers properly. Hope this helps someone down the line.