Wednesday, July 11, 2012

Member Functions



In my daily work I usually use C# however there is some interactions with C++ in the legacy code. Recently a change woke an dormant bug which took a while to track down due to some misdirection.

A simplified but similar error is displayed in this code.
 #include <iostream>  
 #include <list>  
 using namespace std;  
 class A {  
 private:  
      list<int> IntegerList;  
 public:  
      int getListCount() {  
           return IntegerList.size();  
      }  
 };  
 class B {  
 public:  
      A* AClass;  
 };  
 int main() {  
      B* BClass = new B();  
      if (BClass) {  
           cout << BClass->AClass->getListCount() << endl;  
      }  
      return 0;  
 }  

Member function of classes are about the same thing as usual free functions, they just hide that they require a this pointer to the object calling them as their first argument. This pointer can be null which means that the code does not crash when you call a member function on an uninitialized class instance. The crash first occurs when you try to work with the non-existing memory that you think your class contains.

You always want to crash early when a problem occurs, this simplifies the location of the problem. In the code above the crash does not occur until we try to get the size of the integer list. This problem could have easily been avoided with some defensive programming and RIIA.

In the code below I have made sure that the AClass gets assigned when the BClass gets created and even though I'm pretty certain AClass now exists an assert will make sure we crash at a more logical position in the code.  
 #include <iostream>  
 #include <list>  
 #include <cassert>  
 using namespace std;  
 class A {  
 private:  
      list<int> IntegerList;  
 public:  
      int getListCount() {  
           return IntegerList.size();  
      }  
 };  
 class B {  
 public:  
      B() : AClass(new A()) {}  
      virtual ~B() { delete AClass; }  
      A* AClass;  
 };  
 int main() {  
      B* BClass = new B();  
      if (BClass) {  
           assert(BClass->AClass != NULL);  
           cout << BClass->AClass->getListCount() << endl;  
      }  
      return 0;  
 }  


No comments:

Post a Comment