[vtk-developers] [Paraview-developers] Moving vtkMemberFunctionCommand to VTK
David Gobbi
david.gobbi at gmail.com
Wed Oct 6 02:00:19 EDT 2010
For the curious, here is a patch that allows the handler to
be any object. If the object is a vtkObject, then a weak
pointer is used, but for other other objects, dangling
pointers are possible.
David
-------------- next part --------------
diff --git a/Common/Testing/Cxx/TestObservers.cxx b/Common/Testing/Cxx/TestObservers.cxx
index 5828177..ff9ea17 100644
--- a/Common/Testing/Cxx/TestObservers.cxx
+++ b/Common/Testing/Cxx/TestObservers.cxx
@@ -36,6 +36,19 @@ public:
};
vtkStandardNewMacro(vtkHandler);
+class OtherHandler
+{
+public:
+ static vtkstd::map<int, int> EventCounts;
+ static int VoidEventCounts;
+public:
+ void VoidCallback() { this->VoidEventCounts++; }
+ void CallbackWithArguments(vtkObject*, unsigned long event, void*)
+ {
+ this->EventCounts[event]++;
+ }
+};
+
int vtkHandler::VoidEventCounts = 0;
vtkstd::map<int, int> vtkHandler::EventCounts;
@@ -74,7 +87,8 @@ int TestObservers(int, char*[])
volcano->InvokeEvent(1001);
volcano->InvokeEvent(1002);
- volcano->Delete();
+ // remove the final observer
+ volcano->RemoveObserver(event0);
if (vtkHandler::VoidEventCounts == 2 &&
vtkHandler::EventCounts[1000] == 0 &&
@@ -84,6 +98,54 @@ int TestObservers(int, char*[])
cout << "All callback counts as expected." << endl;
return 0;
}
+ else
+ {
+ cerr << "Mismatched callback counts" << endl;
+ volcano->Delete();
+ return 1;
+ }
+
+ // Test again, with a non-VTK object
+
+ OtherHandler *handler2 = new OtherHandler();
+
+ unsigned long event3 = volcano->AddObserver(
+ 1003, handler2, &OtherHandler::VoidCallback);
+ unsigned long event4 = volcano->AddObserver(
+ 1004, handler2, &OtherHandler::CallbackWithArguments);
+ unsigned long event5 = volcano->AddObserver(
+ 1005, handler2, &OtherHandler::CallbackWithArguments);
+
+ volcano->InvokeEvent(1003);
+ volcano->InvokeEvent(1004);
+ volcano->InvokeEvent(1005);
+
+ // let's see if removing an observer works
+ volcano->RemoveObserver(event4);
+ volcano->InvokeEvent(1003);
+ volcano->InvokeEvent(1004);
+ volcano->InvokeEvent(1005);
+
+ // if we delete this non-vtkObject observer, we will
+ // have dangling pointers and will see a crash...
+ // so let's not do that until the events are removed
+
+ volcano->RemoveObserver(event3);
+ volcano->RemoveObserver(event5);
+ delete handler2;
+
+ // delete the observed object
+ volcano->Delete();
+
+ if (OtherHandler::VoidEventCounts == 2 &&
+ OtherHandler::EventCounts[1003] == 0 &&
+ OtherHandler::EventCounts[1004] == 2 &&
+ OtherHandler::EventCounts[1005] == 1)
+ {
+ cout << "All callback counts as expected." << endl;
+ return 0;
+ }
+
cerr << "Mismatched callback counts" << endl;
return 1;
}
diff --git a/Common/vtkObject.h b/Common/vtkObject.h
index f945c53..034a430 100644
--- a/Common/vtkObject.h
+++ b/Common/vtkObject.h
@@ -227,10 +227,11 @@ private:
void operator=(const vtkObject&); // Not implemented.
// Description:
- // Following classes (vtkClassMemberCallbackBase and vtkClassMemberCallback) along with
+ // Following classes (vtkClassMemberCallbackBase and
+ // vtkClassMemberCallback) along with
// vtkObjectCommandInternal are for supporting
- // templated AddObserver() overloads that allow developers to add event
- // callbacks that are class member functions.
+ // templated AddObserver() overloads that allow developers
+ // to add event callbacks that are class member functions.
class vtkClassMemberCallbackBase
{
public:
@@ -239,7 +240,37 @@ private:
virtual void operator()(vtkObject*, unsigned long, void*) = 0;
virtual ~vtkClassMemberCallbackBase(){}
protected:
- vtkWeakPointerBase Handler;
+
+ // Description:
+ // A weak pointer for vtkObjects, and a void pointer
+ // for everything else.
+ class DualPointer
+ {
+ public:
+ void operator=(vtkObjectBase *o)
+ {
+ this->VoidPointer = 0;
+ this->WeakPointer = o;
+ }
+ void operator=(void *o)
+ {
+ this->VoidPointer = o;
+ this->WeakPointer = 0;
+ }
+ vtkObjectBase *GetPointer()
+ {
+ return this->WeakPointer.GetPointer();
+ }
+ void *GetVoidPointer()
+ {
+ return this->VoidPointer;
+ }
+ private:
+ vtkWeakPointerBase WeakPointer;
+ void *VoidPointer;
+ };
+
+ DualPointer Handler;
};
template <class T>
@@ -266,11 +297,23 @@ private:
virtual ~vtkClassMemberCallback() { }
// Called when the event is invoked
- virtual void operator()(vtkObject* caller, unsigned long event, void* calldata)
+ virtual void operator()(
+ vtkObject* caller, unsigned long event, void* calldata)
{
+ // VoidPointer is for a non-vtkObjectBase handler
+ T* handler = static_cast<T*>(this->Handler.GetVoidPointer());
+ // Pointer is weak pointer for a vtkObjectBase handler
if (this->Handler.GetPointer())
{
- T* handler = dynamic_cast<T*>(this->Handler.GetPointer());
+ handler = dynamic_cast<T*>(this->Handler.GetPointer());
+ // For when dynamic_cast fails due to shared object boundaries
+ if (handler == 0)
+ {
+ handler = (T *)this->Handler.GetPointer();
+ }
+ }
+ if (handler)
+ {
if (this->Method1)
{
(handler->*this->Method1)();
More information about the vtk-developers
mailing list