RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Restrain Conversion Operators with the "Indirect Conversion" Idiom-4 : Page 4

Smooth Operator
Let's analyze the return statement. If rawptr isn't NULL, the conversion operator returns a pointer to a member of struct PtrConversion (the precise value of the expression &PtrConversion::valid is immaterial; what matters is that it's a non-NULL constant). However, if rawptr is NULL, the conversion operator returns a NULL pmi. Recall that all pointers to members are implicitly convertible to bool; they aren't bool variables, though. This subtle difference is crucial, as you will see.

After this change, when the following statement executes:

C++ calls ptr.operator pmi() behind the scenes. The return value of type pmi is then silently converted to bool, as expected. However, the following statement no longer compiles, which is exactly what you want:

cout<<"p1 + p2 = "<< p1+p2 <<endl; //compilation error
Here's the secret: C++ guarantees that an operand shall undergo at most one implicit conversion. In the if(ptr) example, you have exactly one implicit conversion from pmi to bool (the very invocation of a conversion operator doesn't constitute an implicit conversion for this matter). However, in the expression p1+p2 two implicit conversions per operand are necessary:
  1. pmi—>bool
  2. bool—>int
As I said, C++ doesn't allow this.

Let's see how this technique eliminates the problems caused by a void* conversion operator:

cout << pf <<endl; //now a compilation error
This statement no longer compiles since there is no overloaded version of operator << that takes pmi or Ptr<T>. Similarly, the following delete expression:

delete pf; //compilation error
doesn't compile because neither pmi nor bool are valid types in a delete expression.

Twisting by the bool
The boost::shared_ptr class uses a slightly different version of the indirect conversion technique. Instead of using a dummy nested struct, it uses a pointer to a member of class shared_ptr itself. In terms of memory footprint, there is no difference between the two versions because the dummy struct is not instantiated anyway. However, some compilers have difficulties coping with pointers to member functions of a class template so the Boost library uses conditional compilation to switch between a pointer to a data member and a pointer to a member function as the target type of the Boolean conversion operator. The bottom line is this: instead of bool, void* or int as the target type of a Boolean conversion operator, use a pointer to member to minimize the perils of implicit conversions.

Danny Kalev is a certified system analyst and software engineer specializing in C++. He was a member of the C++ standards committee between 1997 and 2000 and has since been involved informally in the C++0x standardization process. He is the author of "The ANSI/ISO Professional C++ Programmer's Handbook" and "The Informit C++ Reference Guide: Techniques, Insight, and Practical Advice on C++."
Email AuthorEmail Author
Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date