More C++ Idioms/Print Version 1 More C++ Idioms/Print Version
Total Page:16
File Type:pdf, Size:1020Kb
More C++ Idioms/Print Version 1 More C++ Idioms/Print Version Preface [1] C++ has indeed become too "expert friendly" --- Bjarne Stroustrup, The Problem with Programming , Technology Review, Nov 2006. Stroustrup's saying is true because experts are intimately familiar with the idioms in the language. With the increase in the idioms a programmer understands, the language becomes friendlier to him or her. The objective of this open content book is to present modern C++ idioms to programmers who have moderate level of familiarity with C++, and help elevate their knowledge so that C++ feels much friendlier to them. It is designed to be an exhaustive catalog of reusable idioms that expert C++ programmers often use while programming or designing using C++. This is an effort to capture their techniques and vocabulary into a single work. This book describes the idioms in a regular format: Name-Intent-Motivation-Solution-References, which is succinct and helps speed learning. By their nature, idioms tend to have appeared in the C++ community and in published work many times. An effort has been made to refer to the original source(s) where possible; if you find a reference incomplete or incorrect, please feel free to suggest or make improvements. The world is invited to catalog reusable pieces of C++ knowledge (similar to the book on design patterns by GoF). The goal here is to first build an exhaustive catalog of modern C++ idioms and later evolve it into an idiom language, just like a pattern language. Finally, the contents of this book can be redistributed under the terms of the GNU Free Documentation License. Aimed toward: Anyone with an intermediate level of knowledge in C++ and supported language paradigms Authors • Sumant Tambe talk -- The initiator and lead contributor since July 2007. • Many other C++ aficionados who continuously improve the writeup, examples, and references where necessary. Praise of the Book • "Great and valuable work!" -- Bjarne Stroustrup (February, 2009) Table of Contents Note: synonyms for each idiom are listed in parentheses. 1. Adapter Template 2. Address Of 3. Algebraic Hierarchy 4. Attach by Initialization 5. Barton-Nackman trick 6. Base-from-Member 7. Boost mutant 8. Calling Virtuals During Initialization 9. Capability Query 10. Checked delete 11. Clear-and-minimize 12. Coercion by Member Template 13. Compile Time Control Structures 14. Computational Constructor 15. Concrete Data Type More C++ Idioms/Print Version 2 16. Const auto_ptr 17. Construct On First Use 18. Construction Tracker 19. Copy-and-swap 20. Copy-on-write 21. Counted Body (intrusive reference counting) 22. Curiously Recurring Template Pattern 23. Detached Counted Body (non-intrusive reference counting) 24. Empty Base Optimization 25. Emulated Exception 26. enable-if 27. Envelope Letter 28. Erase-Remove 29. Examplar 30. Execute-Around Pointer 31. Export Guard Macro 32. Expression-template 33. Fake Vtable 34. Fast Pimpl 35. Final Class 36. Free Function Allocators 37. Friendship and the Attorney-Client 38. Function Object 39. Generic Container Idioms 40. Hierarchy Generation 41. Include Guard Macro 42. Inline Guard Macro 43. Inner Class 44. Int-To-Type 45. Interface Class 46. Iterator Pair 47. Making New Friends 48. Metafunction 49. Move Constructor 50. Multi-statement Macro 51. Multiple Member Initialization 52. Member Detector 53. Named Constructor 54. Named External Argument 55. Named Loop (labeled loop) 56. Named Parameter 57. Named Template Parameters 58. Nifty Counter (Schwarz Counter) 59. Non-copyable Mixin 60. Non-member get 61. Non-member Non-friend Function 62. Non-throwing swap More C++ Idioms/Print Version 3 63. Non-Virtual Interface (Public Overloaded Non-Virtuals Call Protected Non-Overloaded Virtuals) 64. nullptr 65. Object Generator 66. Object Template 67. Overload Set Creation 68. Parameterized Base Class (Parameterized Inheritance) 69. Pimpl (Handle Body, Compilation Firewall, Cheshire Cat) 70. Policy Clone (Metafunction wrapper) 71. Policy-based Design 72. Polymorphic Exception 73. Recursive Type Composition 74. Requiring or Prohibiting Heap-based Objects 75. Resource Acquisition Is Initialization (RAII, Execute-Around Object, Scoped Locking) 76. Resource Return 77. Return Type Resolver 78. Runtime Static Initialization Order Idioms 79. Safe bool 80. Scope Guard 81. Substitution Failure Is Not An Error (SFINAE) 82. Shortening Long Template Names 83. Shrink-to-fit 84. Small Object Optimization 85. Smart Pointer 86. Storage Class Tracker 87. Tag Dispatching 88. Temporary Base Class 89. Temporary Proxy 90. The result_of technique 91. Thin Template 92. Traits 93. Type Erasure 94. Type Generator (Templated Typedef) 95. Type Safe Enum 96. Type Selection 97. Virtual Constructor 98. Virtual Friend Function Address Of Intent Find address of a object of a class that has an overloaded unary ampersand (&) operator. Motivation C++ allows overloading of unary ampersand (&) operator for class types. The return type of such an operator need not be the actual address of the object. Intentions of such a class are highly debatable but the language allows it nevertheless. Address-of idiom is way to find the real address of an object irrespective of the overloaded unary More C++ Idioms/Print Version 4 ampersand operator and its access protection. In the example below, main function fails to compile because operator & of nonaddressable class is private. Even if it were accessible, a conversion from its return type double to a pointer would not been possible or meaningful. class nonaddressable { public: typedef double useless_type; private: useless_type operator&() const; }; int main(void) { nonaddressable na; nonaddressable * naptr = &na; // Compiler error here. return 0; } Solution and Sample Code The Address-of idiom retrieves the address of an object using a series of casts. template <class T> T * addressof(T & v) { return reinterpret_cast<T *>(& const_cast<char&>(reinterpret_cast<const volatile char &>(v))); } int main(void) { nonaddressable na; nonaddressable * naptr = addressof(na); // No more compiler error. return 0; } More C++ Idioms/Print Version 5 Known Uses • Boost addressof utility [2] Algebraic Hierarchy Intent To hide multiple closely related algebraic abstractions (numbers) behind a single generic abstraction and provide a generic interface to it. Also Known As • State (Gamma et al.) Motivation In pure object-oriented languages like Smalltalk, variables are run-time bindings to objects that act like labels. Binding a variable to an object is like sticking a label on it. Assignment in these languages is analogous to peeling a label off one object and putting it on another. On the other hand, in C and C++, variables are synonyms for addresses or offsets instead of being labels for objects. Assignment does not mean re-labelling, it means overwriting old contents with new one. Algebraic Hierarchy idiom uses delegated polymorphism to simulate weak variable to object binding in C++. Algebraic Hierarchy uses Envelope Letter idiom in its implementation. The motivation behind this idiom is to be able write code like the one below. Number n1 = Complex (1, 2); // Label n1 for a complex number Number n2 = Real (10); // Label n2 for a real number Number n3 = n1 + n2; // Result of addition is labelled n3 Number n2 = n3; // Re-labelling Solution and Sample Code Complete code showing implementation of Algebraic Hierarchy idiom is shown below. #include <iostream> using namespace std; struct BaseConstructor { BaseConstructor(int=0) {} }; class RealNumber; class Complex; class Number; class Number { friend class RealNumber; friend class Complex; public: Number (); Number & operator = (const Number &n); More C++ Idioms/Print Version 6 Number (const Number &n); virtual ~Number(); virtual Number operator + (Number const &n) const; void swap (Number &n) throw (); static Number makeReal (double r); static Number makeComplex (double rpart, double ipart); protected: Number (BaseConstructor); private: void redefine (Number *n); virtual Number complexAdd (Number const &n) const; virtual Number realAdd (Number const &n) const; Number *rep; short referenceCount; }; class Complex : public Number { friend class RealNumber; friend class Number; Complex (double d, double e); Complex (const Complex &c); virtual ~Complex (); virtual Number operator + (Number const &n) const; virtual Number realAdd (Number const &n) const; virtual Number complexAdd (Number const &n) const; double rpart, ipart; }; class RealNumber : public Number { friend class Complex; friend class Number; RealNumber (double r); RealNumber (const RealNumber &r); virtual ~RealNumber (); virtual Number operator + (Number const &n) const; More C++ Idioms/Print Version 7 virtual Number realAdd (Number const &n) const; virtual Number complexAdd (Number const &n) const; double val; }; /// Used only by the letters. Number::Number (BaseConstructor) : rep (0), referenceCount (1) {} /// Used by user and static factory functions. Number::Number () : rep (0), referenceCount (0) {} /// Used by user and static factory functions. Number::Number (const Number &n) : rep (n.rep), referenceCount (0) { cout << "Constructing a Number using Number::Number\n"; if (n.rep) n.rep->referenceCount++; } Number Number::makeReal (double r) { Number n; n.redefine (new RealNumber (r)); return n; } Number Number::makeComplex (double rpart, double ipart) { Number n; n.redefine (new Complex (rpart, ipart)); return n; } Number::~Number() { if (rep && --rep->referenceCount == 0) delete rep; } More C++ Idioms/Print Version