Click here to Skip to main content
15,867,488 members
Articles / Programming Languages / Visual C++ 9.0

C++ Object destruction event

Rate me:
Please Sign up or sign in to vote.
4.83/5 (3 votes)
8 Aug 2012CPOL3 min read 22.5K   234   14  
vtable modification and destruction event handling

Introduction

This tutorial will attempt to describe how to subscribe for a function invoke event by modifying the object vtable entry and in specific, Demonstrate code sample about hooking for object destructors notification by modifying vtable. Generally this may not be required in C++ coding but for the reader it is additional information about vtables and virtual functions.

Background 

The requirement arise where we have more than 100,000 objects(say Book) stored in a container(say Library) and the Library keeps on modified by a worker thread. The Books from the container is again visualized in GUI control with active Book. The problem rose when the active Book is deleted by worker thread and the GUI thread tries to access the same.
Couple of solutions evaluated and v-table overloading is one among, Internet has lot of topic on discussion about constructing v-table but those may not looks generic since the compiler if free to choose the v-table format. So its decided to use the compiler itself to construct our custom v-table
The only assumption made in this approach is the v-table pointer stored in the first 4 bytes of object memory layout , if this assumption is not correct then the sample code will not work.

Custom v-table 

More complex part of achieving the goal is constructing the v-table but the v-table memory layout might be compiler specific, So we thought of using compiler intelligence to build our custom v-table by inheriting from Book class say book_New(without any state info like member variable or accessing base class member variables) and overload the virtual functions where ever necessary. Now the v-table of book_New shall be hooked into the instance on book object.

Using the code

The sample code is implemented as a template to hook object destruction (which is our primary purpose). The sample code will support hooking only one object and only one observer but the template shall be modified to support multiple objects and hooking other member functions too.

Let’s take look at Book class

C++
class Book {
 
protected: 
   char* name_;
public:
   Book(char* pstr) {
 
      name_=_strdup(pstr);
   };
   Book(){};
   void Display() {printf("Book Name:%s\n",name_);};
 
   virtual ~Book() {
 
      printf("virtual BOOK::~BOOK for :%s\n",name_);
      delete name_ ;
   };
}; 

It’s a simple C++ class remembers the book name and has virtual destructor, the reason for keeping virtual destructor is required since we want to hook for destruction event.

Destructor Hook 

The next piece of code we will look at is the DestructorHook template class

IDestructorObserver interface

C++
class IDestructorObserver {
 
public:
  // invoked when hooked object is destroyed
  virtual void OnDestroy(T* pObj) = 0;
};

It’s a simple C++ interface which has a event call back for destruction and pass the object in question as a parameter. The container should implement this interface in order to get the destruction notification of the object of interest.

Now let’s examine the member variables of the template class

C++
T*    data_; // Generic pointer to be stored
IDestructorObserver* lifeTimeObserver_;
void* vtable_;

data_ refers to the object of interest and here this variable ultimately store the Book object, lifeTimeObserver_ used for dispatching event to the interested parties, and finally vtable_ is used for storing the vtable pointer of the Book to restore upon unhooking. These data members shall be kept on vector or map type of data structure to support multiple object and multiple observers.

Instance method will simply initialize the lifeTimeObserver_ member and returns the Hook objects. The returned hook object shall be used for hooking and object of type T 

C++
static DestructorHook<T>& Instance(IDestructorObserver* proc) {
C++
  staticObj.lifeTimeObserver_ =proc;
  staticObj.name_=_strdup("Librarian Hook");
  return staticObj;
};

Hook method will back up the vtable of the hooked object and keep it for feature reference and then overwrite with our custom vtable as listed below 

C++
void Hook(T* objPtr) {
 
  UnHook();
  // copy first four bytes in MSVC this points to __vfptr
  memcpy(&vtable_,objPtr,sizeof(void*));
  // __vfptr of objPtr with ours
  memcpy(objPtr,this,sizeof(void*));
  data_ = objPtr;
}

Destructor function, this function will get called when the hooked object is deleted, the event shall be dispatched to the subscriber after filtering self destruction

C++
virtual ~DestructorHook() {
 
  // object is getting destroyed
  // so we have to unhook anyway
  staticObj.unHook();
  if(this == staticObj.data_) {
 
     // destructor invoked in the context of hooked object
     // so dispatch event
     staticObj.lifeTimeObserver_->OnDestroy(staticObj.data_);
     // no need to call the destructor as the destruction cycle 
     // continues to call base destructor
     staticObj.data_ = 0;
  }
}

And finally the main function which initializes Books object, the Librarian object will subscribe for destruction event. Later the Book objects destroyed and librarian will get notification for the hooked object 

C++
int _tmain(int argc, _TCHAR* argv[]) {
 
   // initialize chip
   Book * pBook[5];
   char name[20] = {0};
   for(int i = 0 ; i < 5; i++) {
 
      sprintf_s(name,"book%d",(i+1));
      pBook[i] = new Book(name);
   }
 
   Librarian librarian;
   BookDestructorHook& hook_ = BookDestructorHook::Instance(static_cast<BookDestructorHook::IDestructorObserver*>(&librarian));
   hook_.Hook(pBook[3]);
 
 
   printf("Display available books\n");
   for(int i = 0 ; i < 5; i++) {
 
      pBook[i]->Display();
   }
 
   printf("\n\nDeleting all Book Librarian should get notification for\t");
   pBook[3]->Display();
 
   for(int i = 0 ; i < 5; i++) {
 
      delete pBook[i];
   }
 
   return 0;
}

 

Output : 

Image 1

Conclusion 

This article shows a very simple example of how to modify C++ vtable entry to handle object destruction event. Though we didn't used this approach as we preferred reference counting mechanism, But personally believe this alternative approach shall be considered in time critical application where tens of thousands of Book are created and destroyed continuously but container is interested only in a single object. By adapting this approach the remaining object should not carry the burden of reference counting implementation.



License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
India India
Working as a Software technical manager

Comments and Discussions

 
-- There are no messages in this forum --