Is it legal C ++ to validate this pointer in a member function?

I have an application that includes objects of different types of classes. Objects are referenced by pointers. A null pointer means that the associated object does not exist. Currently, calling codes are cumbersome, because every time he uses a pointer to an object, he checks the pointer value for null and takes some appropriate action, it is null. Since the default action to be taken in case of non-existence depends on the type of object, I would prefer to encode it in classes for the objects themselves, and not in the calling program. This leads to the following constructions:

class C { ... void member_func() //non-virtual ! { if (this) { do something with the object ... } else { take some default action } } ... }; 

Obviously, the member function cannot be virtual, because the lookup table does not exist when the object does not exist, and the virtual call failed. But is this code legal C ++ for non-virtual member functions? This seems to work correctly for the compilers I tried it with, but I'm worried about possible intolerance. In the standard, I can not find a clause that either explicitly allows or explicitly prohibits such constructions.

+4
source share
5 answers

this will never be empty in a member function, so the check you perform is useless.

As pointed out by Matthieu M. in the comment, if you do something like this in your code:

 C* c = 0; c->member(); 

This will lead to undefined behavior , and this is something bad .

+12
source

As already noted, this never be a null pointer. If so, you have already invoked undefined behavior. Instead, you can create a set of overloaded functions, for example:

 void DoTheThing(C* cp) { if (cp) cp->member_func(); else { // take some default action } } void DoTheThing(B* bp) { if (bp) bp->some_other_member_func(); else { // take some default action } } 

If the function you want to call has the same name in each class, you can make a static function in each class that performs the default action for that class (all with the same name) and creates a template:

 template<typname T> void DoTheThing(T* tp) { if (tp) tp->member_func(); else T::default_action() } 
+6
source

By default, the code is not legal, but it is used in practice (this is bad practice).

In fact, the MRC IIRC uses these checks internally.

+1
source

Check for the absence of this == NULL . Calling a method using the NULL pointer of an object.

If you want to save checks somewhere, you can put it in a smart pointer class, which can take the appropriate action if the held pointer is NULL. If the “appropriate action” is uniquely determined by the type being held, you can use the feature class to indicate it.

Thus, your NULL checks and their logic are stored together and are not mixed with either the caller or the method code.


 // specialize this to provide behaviour per held type template <typename T> struct MaybeNullDefaultAction { void null_call() { throw std::runtime_error("call through NULL pointer"); } } template <typename T> class MaybeNull: MaybeNullDefaultAction<T> { T *ptr; public: explicit MaybeNull(T *p) : ptr(p) {} T* operator-> () { if (!ptr) null_call(); // null_call should throw to avoid returning NULL here return ptr; } }; 

Unfortunately, I see no way to do this without giving up. It is impossible to intercept function calls for all method names, otherwise I would just return *this from operator-> and do the job in operator() .

+1
source

I think this did not allow it to be done. You asked for links to the standard. I believe that the first thing that is of interest is 9.3.1. Non-stationary member functions, 1 .:

A non-static member function can be called for an object of its type class or for an object of a derived class (section 10) from its type class using the syntax for accessing a class member (5.2.5, 13.3.1.1).

Secondly, see 5.2.5 class member access, 2 .:

The expression E1-> E2 is converted to the equivalent form (* (E1)). E2; the rest of 5.2.5 will only address the first option (dot).

So, if E1 is nullptr, * E1 will not be allowed. So at least that's my guess.

0
source

All Articles