By Matthew WilsonImperfections, Constraints, Definitions, and RecommendationsImperfection: C++ does not provide direct support for constraints. (p. 4)
Imperfection: C++ does not provide suitable support for postconditions. (p. 15)
Recommendation: Use assertions to assert truths about the structure of the code, not about runtime behavior. (p. 21)
Definition: Resource Release Is Destruction is a mechanism that takes advantage of C++'s support for automatic destruction to ensure the deterministic release of resources associated with an instance of an encapsulating type. (p. 46)
Definition: Resource Acquisition Is Initialization is a mechanism that takes advantage of C++'s support for construction and automatic destruction to ensure the deterministic release of resources associated with an instance of an encapsulating type. It can be thought of as a superset of the RRID mechanism. (p. 51)
Definition: Encapsulated types provide access to, and manipulation of, instance state via a robust public interface, and client code should not, and need not, have access to the internal member state of instances of such types. Encapsulated types provide a notionally complete separation between logical and physical state. (p. 60)
Definition: Value Type (p. 62)
Instances cannot polymorphically substitute, or be substituted by, instances of another type at run time.
Instances can be created as, or later made to be, copies of another instance.
Each instance has a logically separate identity. Any change to the logical state of one instance does not result in a change to the logical state of another. (Physical state may be shared according to implementation-specific design decisions, so long as such sharing does not invalidate the logical separation.)
Instances can be (in)equality compared with any other instances, and even with themselves. Equality (and inequality) is reflexive, symmetric, and transitive.
Imperfection: The C++ standard does not define an ABI, leading to wholesale incompatibilities between many comxpilers on many platforms. (p. 92)
Imperfection: C++ is not a suitable module-interface language. (p. 121)
Imperfection: C and C++ say nothing about threading. (p. 132)
Imperfection: C++ does not provide a mechanism for controlling global object ordering. (p. 158)
Recommendation: Don't rely on global object initialization ordering. Do utilize global object initialization ordering tracing mechanisms anyway. (p. 161)
Recommendation: Don't create threads during global object initialization. (p. 166)
Imperfection: Function-local static instances of classes with nontrivial constructors are not thread-safe. (p. 171)
Imperfection: The support for Empty Base Optimization (EBO) flavors is not universal, and varies significantly between compilers. (p. 183)
Imperfection: C and C++ are missing a byte type. (p. 191)
Imperfection: C and C++ need fixed-sized integer types. (p. 195)
Imperfection (reprise): C++ needs fixed sized types that are different to, and not implicitly interconvertible with, its built-in integral types. (p. 196)
Imperfection: C and C++ do not provide large fixed-sized integer types. (p. 200)
Imperfection: bool should be the same size as int. (p. 205)
Imperfection: C and C++ do not provide a dimensionof() operator (for array types). (p. 207)
Imperfection: Inability to distinguish between arrays and pointers can result in static array size determination being applied to pointers or class types, yielding incorrect results. (p. 211)
Imperfection: C and C++ arrays decay into pointers when passed to functions. (p. 214)
Imperfection: C++'s array/pointer duality, combined with its support for polymorphic handling of inherited types, is a hazard against which the compiler provides no assistance. (p. 218)
Imperfection: C++ does not support multi-dimensional arrays. (p. 224)
Imperfection: C++ needs a null keyword, which can be assigned to, and equality compared with, any pointer type, and with no non-pointer types. (p. 229)
Imperfection: Having more than one discrete value for the Boolean type is dangerous. (p. 236)
Imperfection: Specification of the size of integer types as implementation dependent in C/C++ reduces the portability of integer literals. (p. 238)
Imperfection: C++ compilers do not agree on the syntax for suffixes of integer literals larger than those that will fit into (unsigned) long. (p. 239)
Constraint: C and C++ do not guarantee to ensure that identical string literals will be folded within a single link unit, and cannot do so across separate link units. (p. 242)
Constraint: Casting away constness of a constant object is not legal, and will likely lead to unintended consequences. (p. 245)
Constraint: Constants of class type are evaluated as immutable global objects, rather than as compile-time constants. Failure to be mindful of this distinction is hazardous. (p. 246)
Recommendation: Avoid using enum values larger than those that will fit in an int. (p. 248)
Imperfection: C++ does not support member constants of floating-point type. (p. 249)
Constraint: C++ does not support member constants of class type. (p. 250)
Recommendation: Never attempt to simulate class-type member constants with function local static objects. (p. 251)
Imperfection: C++ does not provide access control between types involved in a composition relationship. (p. 257)
Imperfection: The introduction of new keywords into the language requires contingency mechanisms to maintain portability. (p. 268)
Imperfection: Abuse of C++'s last-known access specifier mechanism leads to code that is hard to use and hard to maintain. (p. 271)
Imperfection: Implicitly interpreting non-Boolean (sub-)expressions leads to failure to be mindful of the values of certain types, with a consequent propensity to over-engineer user-defined types. (p. 274)
Imperfection: The implicit interpretation of scalar types as Boolean in conditional statements facilitates erroneous assignment caused by syntax errors. (p. 275)
Imperfection: The contradiction between the old and new for-statement rules results in non-portable code. (p. 278)
Imperfection: for statements requiring initializers of two or more types render the new for-scoping rule irrelevant. (p. 279)
Definition: Conceptual type definitions define logically distinct types. (p. 289)
Definition: Contextual type definitions define types that correspond to well-known concepts, relative to specific contexts. Such types act as descriptions of the nature (type and/or behavior) of their host contexts. (p. 291)
Imperfection: C++ provides no type-safety for the use of conceptual defined types, except where such types have incompatible underlying types. (p. 294)
Imperfection: C++ does not support overloading on conceptually defined types, except where such types happen to have different underlying types on a particular platform. (p. 294)
Recommendation: Avoid making conceptual typedefs that are comprised of contextual typedefs. (p. 304)
Imperfection: Logically related types in C++ can, and usually do, have incompatible interfaces and operations, rendering a generalized approach to type manipulation sometimes difficult, and often impossible. (p. 341)
Definition: Attribute Shims (pp. 343344)
Attribute shims retrieve attributes or states of instances of the types for which they are defined.
The names of attribute shims take the form get_xxx, where xxx represents the particular attribute being accessed (except where they form part of a composite shim concept).
The values returned from attribute shims are always valid outside the instance of the shim, in cases where the shim is implemented by the creation of a temporary object.
Definition: Logical Shims (p. 346)
Logical shims are a refinement of attribute shims in that they report on the state of an instance to which they are applied.
The names of logical shims take the form of an interrogative coupled with the particular attribute or state being queried. Examples would be is_open, has_element, is_null.
Definition: Control Shims (p. 347)
Control shims define operations that are applied to the instances of the types for which they are defined.
The names of control shims take the form of an imperative element coupled with the particular attribute or state being modified. Examples would be make_empty dump_contents.
Definition: Conversion Shims (p. 348)
Conversion shims operate by converting instances of the range of compatible types to a single target type.
The names of attribute shims take the form to_xxx, where xxx is the name of, or represents, the target type, for example, to_int.
The values returned from conversion shims may be provided by intermediate temporary objects, so must only be used from within the expression containing the shim.
Definition: Composite Shims (p. 350)
Composite shims are a combination of two or more fundamental shim concepts.
The names of composite shims do not have a fixed convention, but rather take a name indicative of their purpose.
Composite shims obey the most restrictive rule, or combination of rules, from their constituent shims.
Definition: Access Shims (p. 351)
Access shims are a combination of Attribute and Conversion shims, which are used to access the values of the instances of the types for which they are defined.
The values may have to be synthesised via conversion shims.
The values returned from access shims may be provided by intermediate temporary objects, so must only be used from within the expression containing the shim.
Definition: Veneers (p. 364)
A veneer is a template class with the following characteristics:
It derives, usually publicly, from its primary parameterizing type.
It accommodates, and adheres to, the polymorphic nature of its primary parameterizing type. This means that a veneer cannot define any virtual methods of its own, though it can override those defined by its primary parameterizing type.
It may not define any non-static member variables.
The consequence of 2 & 3 is that a veneer may not change the memory footprint of its primary parameterizing type, and this is achieved by virtue of the Empty Derived Optimization (EDO; see section 12.4), a very widely supported optimization. In other words, instances of a veneer composite have the same size as the primary parameterizing type.
Definition: Bolt-ins (p. 375)
Bolt-ins are template classes with the following characteristics:
They derive, usually publicly, from their primary parameterizing type.
They accommodate the polymorphic nature of their primary parameterizing type. Usually they also adhere to the nature, but this is not always the case, and they may define virtual methods of their own, in addition to overriding those defined by the primary parameterizing type.
They may increase the footprint of the primary parameterizing type by the definition of member variables, virtual functions and additional inheritance from non-empty types.
Imperfection: The C++ template mechanism instantiates a template based on the arguments to it, and takes no account of how, or in what form, those arguments are subsequently used within the templates. This can lead to the generation of inefficient and/or erroneous code since temporary instances of class type may be created during the forwarding of arguments through the template. (p. 387)
Imperfection: Overloading operator &()
breaks encapsulation. (p. 425)
Imperfection: Provision of implicit conversion operator(s) to pointer type(s) along with subscript operator(s) is non-portable. (p. 434)
Imperfection: Some C++ compilers will substitute prefix increment/decrement overloaded operators at the call site in place of absent postfix equivalents. (p.440)
Imperfection: Overloading the && and || operators for class types represents an invisible breaking of short-circuit evaluation. (p. 454)
Imperfection: C and C++ make you choose between performance and flexibility when allocating memory. (p. 476)
Imperfection: C/C++ does not support dynamically dimensioned multidimensional arrays. (p. 491)
Recommendation: An array size shim should always be used when determining the sizes of arrays, as all other approaches do not generalize for both built-in and user defined array types. (p. 505)
Imperfection: C++ does not support local functor classes (to be used with template algorithms). (p. 514)
Definition: Type Tunneling is a mechanism whereby two logically related but physically unrelated types can be made to interoperate via the use of Access Shims. The shim allows an external type to be tunnelled through an interface and presented to the internal type in a recognized and compatible form. (p. 518)
Definition: A Range represents a bounded collection of elements, which may be accessed in an incremental fashion. It encapsulates a logical rangethat is, a beginning and an end point, along with rules for how to walk through it (move from the beginning to the end point)and embodies a single entity with which client code may access the values contained within the range. (p. 521522)
Imperfection: C++ does not provide properties. (p. 531)
Imperfections, Constraints, Definitions, and RecommendationsImperfection: C++ does not provide direct support for constraints. (p. 4)
Imperfection: C++ does not provide suitable support for postconditions. (p. 15)
Recommendation: Use assertions to assert truths about the structure of the code, not about runtime behavior. (p. 21)
Definition: Resource Release Is Destruction is a mechanism that takes advantage of C++'s support for automatic destruction to ensure the deterministic release of resources associated with an instance of an encapsulating type. (p. 46)
Definition: Resource Acquisition Is Initialization is a mechanism that takes advantage of C++'s support for construction and automatic destruction to ensure the deterministic release of resources associated with an instance of an encapsulating type. It can be thought of as a superset of the RRID mechanism. (p. 51)
Definition: Encapsulated types provide access to, and manipulation of, instance state via a robust public interface, and client code should not, and need not, have access to the internal member state of instances of such types. Encapsulated types provide a notionally complete separation between logical and physical state. (p. 60)
Definition: Value Type (p. 62)
Instances cannot polymorphically substitute, or be substituted by, instances of another type at run time.
Instances can be created as, or later made to be, copies of another instance.
Each instance has a logically separate identity. Any change to the logical state of one instance does not result in a change to the logical state of another. (Physical state may be shared according to implementation-specific design decisions, so long as such sharing does not invalidate the logical separation.)
Instances can be (in)equality compared with any other instances, and even with themselves. Equality (and inequality) is reflexive, symmetric, and transitive.
Imperfection: The C++ standard does not define an ABI, leading to wholesale incompatibilities between many comxpilers on many platforms. (p. 92)
Imperfection: C++ is not a suitable module-interface language. (p. 121)
Imperfection: C and C++ say nothing about threading. (p. 132)
Imperfection: C++ does not provide a mechanism for controlling global object ordering. (p. 158)
Recommendation: Don't rely on global object initialization ordering. Do utilize global object initialization ordering tracing mechanisms anyway. (p. 161)
Recommendation: Don't create threads during global object initialization. (p. 166)
Imperfection: Function-local static instances of classes with nontrivial constructors are not thread-safe. (p. 171)
Imperfection: The support for Empty Base Optimization (EBO) flavors is not universal, and varies significantly between compilers. (p. 183)
Imperfection: C and C++ are missing a byte type. (p. 191)
Imperfection: C and C++ need fixed-sized integer types. (p. 195)
Imperfection (reprise): C++ needs fixed sized types that are different to, and not implicitly interconvertible with, its built-in integral types. (p. 196)
Imperfection: C and C++ do not provide large fixed-sized integer types. (p. 200)
Imperfection: bool should be the same size as int. (p. 205)
Imperfection: C and C++ do not provide a dimensionof() operator (for array types). (p. 207)
Imperfection: Inability to distinguish between arrays and pointers can result in static array size determination being applied to pointers or class types, yielding incorrect results. (p. 211)
Imperfection: C and C++ arrays decay into pointers when passed to functions. (p. 214)
Imperfection: C++'s array/pointer duality, combined with its support for polymorphic handling of inherited types, is a hazard against which the compiler provides no assistance. (p. 218)
Imperfection: C++ does not support multi-dimensional arrays. (p. 224)
Imperfection: C++ needs a null keyword, which can be assigned to, and equality compared with, any pointer type, and with no non-pointer types. (p. 229)
Imperfection: Having more than one discrete value for the Boolean type is dangerous. (p. 236)
Imperfection: Specification of the size of integer types as implementation dependent in C/C++ reduces the portability of integer literals. (p. 238)
Imperfection: C++ compilers do not agree on the syntax for suffixes of integer literals larger than those that will fit into (unsigned) long. (p. 239)
Constraint: C and C++ do not guarantee to ensure that identical string literals will be folded within a single link unit, and cannot do so across separate link units. (p. 242)
Constraint: Casting away constness of a constant object is not legal, and will likely lead to unintended consequences. (p. 245)
Constraint: Constants of class type are evaluated as immutable global objects, rather than as compile-time constants. Failure to be mindful of this distinction is hazardous. (p. 246)
Recommendation: Avoid using enum values larger than those that will fit in an int. (p. 248)
Imperfection: C++ does not support member constants of floating-point type. (p. 249)
Constraint: C++ does not support member constants of class type. (p. 250)
Recommendation: Never attempt to simulate class-type member constants with function local static objects. (p. 251)
Imperfection: C++ does not provide access control between types involved in a composition relationship. (p. 257)
Imperfection: The introduction of new keywords into the language requires contingency mechanisms to maintain portability. (p. 268)
Imperfection: Abuse of C++'s last-known access specifier mechanism leads to code that is hard to use and hard to maintain. (p. 271)
Imperfection: Implicitly interpreting non-Boolean (sub-)expressions leads to failure to be mindful of the values of certain types, with a consequent propensity to over-engineer user-defined types. (p. 274)
Imperfection: The implicit interpretation of scalar types as Boolean in conditional statements facilitates erroneous assignment caused by syntax errors. (p. 275)
Imperfection: The contradiction between the old and new for-statement rules results in non-portable code. (p. 278)
Imperfection: for statements requiring initializers of two or more types render the new for-scoping rule irrelevant. (p. 279)
Definition: Conceptual type definitions define logically distinct types. (p. 289)
Definition: Contextual type definitions define types that correspond to well-known concepts, relative to specific contexts. Such types act as descriptions of the nature (type and/or behavior) of their host contexts. (p. 291)
Imperfection: C++ provides no type-safety for the use of conceptual defined types, except where such types have incompatible underlying types. (p. 294)
Imperfection: C++ does not support overloading on conceptually defined types, except where such types happen to have different underlying types on a particular platform. (p. 294)
Recommendation: Avoid making conceptual typedefs that are comprised of contextual typedefs. (p. 304)
Imperfection: Logically related types in C++ can, and usually do, have incompatible interfaces and operations, rendering a generalized approach to type manipulation sometimes difficult, and often impossible. (p. 341)
Definition: Attribute Shims (pp. 343344)
Attribute shims retrieve attributes or states of instances of the types for which they are defined.
The names of attribute shims take the form get_xxx, where xxx represents the particular attribute being accessed (except where they form part of a composite shim concept).
The values returned from attribute shims are always valid outside the instance of the shim, in cases where the shim is implemented by the creation of a temporary object.
Definition: Logical Shims (p. 346)
Logical shims are a refinement of attribute shims in that they report on the state of an instance to which they are applied.
The names of logical shims take the form of an interrogative coupled with the particular attribute or state being queried. Examples would be is_open, has_element, is_null.
Definition: Control Shims (p. 347)
Control shims define operations that are applied to the instances of the types for which they are defined.
The names of control shims take the form of an imperative element coupled with the particular attribute or state being modified. Examples would be make_empty dump_contents.
Definition: Conversion Shims (p. 348)
Conversion shims operate by converting instances of the range of compatible types to a single target type.
The names of attribute shims take the form to_xxx, where xxx is the name of, or represents, the target type, for example, to_int.
The values returned from conversion shims may be provided by intermediate temporary objects, so must only be used from within the expression containing the shim.
Definition: Composite Shims (p. 350)
Composite shims are a combination of two or more fundamental shim concepts.
The names of composite shims do not have a fixed convention, but rather take a name indicative of their purpose.
Composite shims obey the most restrictive rule, or combination of rules, from their constituent shims.
Definition: Access Shims (p. 351)
Access shims are a combination of Attribute and Conversion shims, which are used to access the values of the instances of the types for which they are defined.
The values may have to be synthesised via conversion shims.
The values returned from access shims may be provided by intermediate temporary objects, so must only be used from within the expression containing the shim.
Definition: Veneers (p. 364)
A veneer is a template class with the following characteristics:
It derives, usually publicly, from its primary parameterizing type.
It accommodates, and adheres to, the polymorphic nature of its primary parameterizing type. This means that a veneer cannot define any virtual methods of its own, though it can override those defined by its primary parameterizing type.
It may not define any non-static member variables.
The consequence of 2 & 3 is that a veneer may not change the memory footprint of its primary parameterizing type, and this is achieved by virtue of the Empty Derived Optimization (EDO; see section 12.4), a very widely supported optimization. In other words, instances of a veneer composite have the same size as the primary parameterizing type.
Definition: Bolt-ins (p. 375)
Bolt-ins are template classes with the following characteristics:
They derive, usually publicly, from their primary parameterizing type.
They accommodate the polymorphic nature of their primary parameterizing type. Usually they also adhere to the nature, but this is not always the case, and they may define virtual methods of their own, in addition to overriding those defined by the primary parameterizing type.
They may increase the footprint of the primary parameterizing type by the definition of member variables, virtual functions and additional inheritance from non-empty types.
Imperfection: The C++ template mechanism instantiates a template based on the arguments to it, and takes no account of how, or in what form, those arguments are subsequently used within the templates. This can lead to the generation of inefficient and/or erroneous code since temporary instances of class type may be created during the forwarding of arguments through the template. (p. 387)
Imperfection: Overloading operator &()
breaks encapsulation. (p. 425)
Imperfection: Provision of implicit conversion operator(s) to pointer type(s) along with subscript operator(s) is non-portable. (p. 434)
Imperfection: Some C++ compilers will substitute prefix increment/decrement overloaded operators at the call site in place of absent postfix equivalents. (p.440)
Imperfection: Overloading the && and || operators for class types represents an invisible breaking of short-circuit evaluation. (p. 454)
Imperfection: C and C++ make you choose between performance and flexibility when allocating memory. (p. 476)
Imperfection: C/C++ does not support dynamically dimensioned multidimensional arrays. (p. 491)
Recommendation: An array size shim should always be used when determining the sizes of arrays, as all other approaches do not generalize for both built-in and user defined array types. (p. 505)
Imperfection: C++ does not support local functor classes (to be used with template algorithms). (p. 514)
Definition: Type Tunneling is a mechanism whereby two logically related but physically unrelated types can be made to interoperate via the use of Access Shims. The shim allows an external type to be tunnelled through an interface and presented to the internal type in a recognized and compatible form. (p. 518)
Definition: A Range represents a bounded collection of elements, which may be accessed in an incremental fashion. It encapsulates a logical rangethat is, a beginning and an end point, along with rules for how to walk through it (move from the beginning to the end point)and embodies a single entity with which client code may access the values contained within the range. (p. 521522)
Imperfection: C++ does not provide properties. (p. 531)