Skip to main content

Posts

Showing posts from April, 2007

Boost C++ Idioms

This time lets take a brief look at some nifty C++ idioms in the Boost peer-reviewed libraries. We will talk about Boost Base-from-Member idiom, Boost Safe bool idiom, Boost Named External Argument idiom, Boost Non-member get() idiom, Boost Meta-function wrapper idiom, Boost Iterator pair idiom, and the Boost Mutant idiom. Boost Base-from-Member idiom This idiom is used to initialize a base class from a data-member of the derived class. It sounds contradictory to the rules of C++ language and that is the reason why this idiom is present. It basically boils down to pushing the parameter data member in a private base class and put that private base class before the dependent base class in the derivation order. A generalization of the technique can be found here . Boost Safe bool idiom Many authors have talked about the evils of type conversion functions defined in a class. Such functions allow the objects of that type to participate in nonsensical expressions. One good example is in sta

new, delete, custom memory allocation, and exception safety

This post will hopefully push you ahead to a higher level of expertise in memory management mechanics of C++ and exception safety. Here we go... Some warm-up: Consider a function void func (T*, U*); and int main() { func (new T, new U); // line 1 } Calling the function like in line 1 is a bad idea because parameter evaluation sequence is not standard and therefore it memory allocation of second new (it could T or U) fails, we have a blatant memory leak. What to do? Lets use our silver bullet: auto_ptr! but it fails too for the same reasons. Consider a function void func (std::auto_ptr <T>, std::auto_ptr <U>); Now it is possible that, even before any auto_ptrs are constructed, new may throw or a constructor may throw and all efforts go in vain. Details can be found in Hurb Sutter's More Excetional C++: Item 20-21. So we should separate the allocation and the function call. auto_ptr <T> t1 = new T; auto_ptr <U> u1 = new U; func (t1, u1); That's no better e

Non-Virtual Interface (NVI) idiom and the design intent

Assuming that the philosophy of Non-Virtual Interface (NVI) idiom is strictly adhered I came up with a table that summarizes the design intent in terms of access modifiers and virtuality. Strict adherence of NVI allows separation of the interface of a class into two distinct interfaces: client interface (public non-virtual) and subclass interface (protected virtual/non-virtual). Such a structure helps mitigate the Fragile Base Class (FBC) Interface problem if discipline is followed. Its only downside is a little bit of code bloat. More about this approach of resolving FBC can be found here .   non-virtual virtual but not pure pure virtual without body pure virtual with body Public Clients expect substitutability. Extension points are encapsulated.  Subclasses should stay away from this if an equivalent protected function using NVI is given. Clients expect substitutability. Extension points are visible. Subclasses can optionally exte

Virtuality is an implementation detail !

There are many ways of achieving separation of interface from implementation: 1. Using Interface Definition Language (IDL) as in CORBA 2. Bridge Pattern (GoF) 3. Pimpl idiom 4. Handle/Body idiom 5. Envelope/Letter idiom 6. Template Method pattern (GoF) The Template Method way of achieving this is a bit tricky. It basically boils down to a few class design guidelines based on access modifiers, virtuality and language expressibility. It is also known as Non-Virtual Interface (NVI) idiom. 1. Prefer to make interfaces non-virtual, using Template Method. 2. Prefer to make virtual functions private. 3. Only if derived classes need to invoke the base implementation of a virtual function, make the virtual function protected. 4. A base class destructor should be either public and virtual, or protected and non-virtual. For more information please see: Virtuality and Virtually Yours. A few more elemental base class idioms can be found here . A comparison of the above approaches can be found