C++ assert(this)

Moderator
Posts: 371
Joined: 2006.08
Post: #1
I've been using wxWidgets lately at work, and they have a very....different way of doing some things. One line of code in particular caught my eye; it's included as the first line of code in every member function:
Code:
assert(this);

This bugs me. I can't think of a logical reason why the above code wouldn't detect calling a method on a NULL pointer, but for some reason it just seems....wrong.

Is something like this good practice? If it works well, I'm thinking about adding something similar to my code, or possibly even overloading the -> and * operators to automatically test for a this pointer that is NULL.

Thanks Smile
-wyrmmage

Worlds at War (Current Project) - http://www.awkward-games.com/forum/
Quote this message in a reply
Moderator
Posts: 1,140
Joined: 2005.07
Post: #2
Overloading the * and -> operators won't do you any good. Those operators act on the objects themselves, not the pointers. For example:
Code:
Foo *foo = new Foo;
foo->something();
will only call the member function something. Meanwhile:
Code:
Foo foo;
foo->something();
will call operator->, then call something() on the pointer that's returned.

Besides, it is also possible to have a NULL reference. (so using "." can end up dereferencing NULL) For example:
Code:
Foo &foo = *getFoo();
foo.something();
If getFoo() returns NULL, and it's blindly dereferenced, you won't get any issues at runtime until the this pointer is dereferenced in the member function something(). (assuming this even is dereferenced. If this is never dereferenced in something() or another function it calls and something() isn't a virtual function it won't crash at all)

All that said, it is possible for this to not be NULL, but to have the original pointer still be NULL. The main case I can think of is multiple inheritance. Take the following:
Code:
class Foo
{
public:
   void printFoo() const
   {
      printf("0x%X\n", this);
   }
private:
   int a;
};

class Bar
{
public:
   void printBar() const
   {
      printf("0x%X\n", this);
   }
private:
   int b;
};

class FooBar : public Foo, public Bar
{
};

...

FooBar *fooBar = NULL;
fooBar->printFoo();
fooBar->printBar();
Since FooBar contains both Foo and Bar, the members will be listed one after another. (it might be implementation defined, but there could be a defined order based on the order you list them in the inheritance list) In this example, lets say the memory layout is the contents of Foo followed by the contents of Bar. This means that the address of the member variable "a" will be at an offset of 0 bytes, while the member variable "b" will be at an offset of 4 bytes from the point of view of FooBar. From the point of view of both Foo and Bar, though, their respective member variables are at an offset of 0 bytes. Therefore, in the above example, the call to printFoo() will print out "0x0", while the call to printBar() will print out "0x4". Note that multiple inheritance will also break things such as casting between types using reinterpret_cast or casting with void pointers. C style casts, static_cast, and dynamic_cast are all fine, though, assuming you don't have any steps with a void pointer. The only case using a void pointer will work correctly is if you cast it to the type it originally was before casting it to anything else. You can check out more info on these issues here. (http://carcino.gen.nz/tech/cpp/multiple_...e_this.php)

Note that even uses of multiple inheritance as an interface, without any actual data, will cause this problem. This is because the object needs to store a pointer to the virtual function table (think of it as a hidden member variable) and a pointer is required for each type hierarchy it inherits from that has virtual functions.

However, if you only use multiple inheritance for interfaces, then checking the this pointer against NULL should always work assuming the following are true: the layout in memory of the inherited classes is always defined to be in the same order as the classes are listed in the inheritance list (aka: class FooBar : public Foo, public Bar; I'm not sure if it's a valid assumption or not), you always list the class that holds the data first, and you don't have any default implementations of functions in your base interface classes. What I mean for the last case is if you have this as your interface class:
Code:
class Foo
{
public:
   virtual something() = 0;
   virtual interesting()
   {
      assert(this);
      something();
   }
};
Though this is an interface, with the only thing special about it a default implementation of a function, it will still break with the assert if it's used in multiple inheritance for the reasons stated above.
Quote this message in a reply
Hog
Member
Posts: 151
Joined: 2002.09
Moderator
Posts: 371
Joined: 2006.08
Post: #4
Sorry for not replying earlier....I'm in the process of moving to Tucson, Arizona, so I've been without internet for a couple of days.

Very interesting stuff! Thanks for the links Smile

Akb: Good to know....looks like I need to go read up on operator overloading again. That article is exactly the thing I was looking for. Thanks for the link Smile

Oh, and since when do you only have sixty-five posts, akb? I thought you posted fairly often Annoyed

Worlds at War (Current Project) - http://www.awkward-games.com/forum/
Quote this message in a reply
Moderator
Posts: 1,140
Joined: 2005.07
Post: #5
wyrmmage Wrote:Sorry for not replying earlier....I'm in the process of moving to Tucson, Arizona, so I've been without internet for a couple of days.

Very interesting stuff! Thanks for the links Smile

Akb: Good to know....looks like I need to go read up on operator overloading again. That article is exactly the thing I was looking for. Thanks for the link Smile

Oh, and since when do you only have sixty-five posts, akb? I thought you posted fairly often Annoyed
Also notice my join date. Rasp

My account was spontaneously deleted about a month ago, and I had to set it back up. Carlos was a big help in getting my old posts hooked up to my new account, but some stuff like the postcount aren't quite right. (which isn't that big of a deal) In reality I joined (IIRC) in 2005 and have closer to 1300 posts.
Quote this message in a reply
Moderator
Posts: 371
Joined: 2006.08
Post: #6
ah, that explains it Smile

Worlds at War (Current Project) - http://www.awkward-games.com/forum/
Quote this message in a reply
Post Reply