TITLE: is it worth testing "this" for NULL (Newsgroups: comp.std.c++, 7 Jul 98) BASJES: Basjes@nlr.nl (Niels Basjes) >> I had the following idea to make my C++ code more robust : >> Check if the "this" pointer is NULL inside a regular (non static) >> member function (example of what I have in mind at the bottom). >> >> Is this kind of checking allowed (according to the standards) and how >> portable is it between different compilers that are currently >> available (It works on Sun CC 4.1 and GCC 2.7.2) ? CLAMAGE: Steve Clamage > "this" is a pointer, and any pointer can be compared for > equality to NULL. "this" will compare equal if and only if > it is a null pointer. That isn't the problem. > > The problem is the test is nearly useless. Calling a non-static > member function from a null pointer has undefined results. > The test will protect against the invalid call only sometimes, > and with some compilers. If the function is virtual, the call won't > succeed, and you never get to the point where you check for null. > > The problem can also show up when calling a non-virtual function > of a base class from a null pointer of derived-class type. > Since calling the function via a null pointer is invalid, > compilers typically do not check for null before applying > the pointer adjustment. (Doing so would slow down every function > call.) The function gets called with a non-null pointer that doesn't > point to an object. Boom! > > Null pointer checks should occur before the pointer is used > in any way, not after. TRIBBLE: dtribble@technologist.com Quite right. On the other hand, you might care to check that 'this' points to an object of the *expected* type, once the call does succeed. This check is useful for the following reasons: 1. Client code may be out of date with respect to your library code, meaning that client code that contructs an object of type Foo might be compiled with an obsolete header file, so his Foo object is different that what your library code expects. Or the other way around, the client could be compiled using the newer header file for the class but his program is linked with an obsolete version of your library. This is sometimes referred to as an "object versioning" or "version mismatch" problem. 2. Pointers to deleted objects might not get reset to null, and might get used later under the assumption that they still point to live objects. In this situation, the pointers are no longer pointing to proper objects. Worse, they could be pointing to objects of a completely different type that reside in the same memory that used to be occupied by the old object. 3. Object data might get corrupted. One way to check that an object is of the expected type is to have it contain a "magic number" member with a value that is unique to that class. If the 'this' object doesn't have the correct magic number, then you know that the object is not correct and something went wrong (probably a bad pointer to a deleted object). It a good idea to set the magic number member to the correct value in the constructor, and to set it to a bogus (different) value in the destructor. [ One responder suggested using typeid() for this. -adc ] You can also check that the object is of the expected version, to detect client/library version mismatches. One way is to store the version number as a private member in the object, and have every member function validate it before they access any other members of the object. Finally, you can go all out and put some sort of checksum in the object, in order to detect object corruption. This is expensive because the checksum must be recomputed every time you change a member of the object. But for really critical applications, this may be an acceptable cost for reliability. Be warned, also, that changing the members of a class (for a new release of your library) can spell disaster for old client code, especially if the class has virtual member functions. Changing class declarations for new releases must be planned carefully, starting at version 1.0. Another problem to consider is that NULL is only one invalid pointer value out of all the possible invalid values (as many as 2^32 bad values are possible on 32-bit systems). Calling a member function via a corrupt pointer might be impossible to detect until it's too late. The best strategy is to try to restrict your client's access to your objects as much as possible. But be aware that you can't completely prevent clients from handing you bad pointers.