More C++ Idioms/Construction Tracker
From Wikibooks, the open-content textbooks collection
Contents |
[edit]
Construction Tracker
[edit] Intent
To identify the data member that throws an exception when initialization of two or more objects in the constructor's initialization list can throw the same exception type
[edit] Also Known As
[edit] Motivation
When two or more objects are initialized in a constructor's initialization list and all of them can throw the same exception (std::exception), tracking which one of them failed become a tricky issue as there can be only one try block surrounding the initialization list. Such a try block has a special name called 'constructor try block', which is nothing but a 'function-try block'.
[edit] Solution and Sample Code
Construction Tracker idiom uses a simple technique to track successful construction on objects in the initialization list. A counter is simply incremented as constructors of objects finish successfully one-by-one. It cleverly uses bracket operator to inject the counter increments in between calls to the constructors all being invisible to the user of the class.
#include <iostream> #include <stdexcept> struct B { B (char const *) { throw std::runtime_error("B Error"); } }; struct C { C (char const *) { throw std::runtime_error("C Error"); } }; class A { B b_; C c_; enum TrackerType { NONE, ONE, TWO }; public: A( TrackerType tracker = NONE) try // A constructor try block. : b_((tracker = ONE, "hello")) // Can throw std::exception , c_((tracker = TWO, "world")) // Can throw std::exception { assert(tracker == TWO); // ... constructor body ... } catch (std::exception const & e) { if (tracker == ONE) { std::cout << "B threw: " << e.what() << std::endl; } else if (tracker == TWO) { std::cout << "C threw: " << e.what() << std::endl; } throw; } }; int main (void) { try { A a; } catch (std::exception const & e) { std::cout << "Caught: " << e.what() << std::endl; } return 0; }
The double parentheses is how the bracket operator is used to place in the assignment to the tracker. This idiom critically depends upon the constructor of B and C taking at least one parameter. If class B and C does not take parameters, then an adapter class needs to be written such that it the adapter class will accept a dummy parameter and calling the default parameters of B and C. Such an adapter can be written using More C++ Idioms/Parameterized Base Class idiom using mixin-from-below technique. The adapter class can also be completely encapsulated inside class A. In the consturctor of class A, the tracker parameter has a default value and therefore it does no bother the user.