Als Vorbereitung für die kommenden Coding Dojos werden wir dieses Mal
eine etwas tiefere Einführung in Test-Driven-Development (TDD) geben und
Beispiele und Übungen mit Googletest und Googlemock machen.
Am letzten Meeting haben wir uns ein paar C++ Idiome angeschaut. Hier eine Zusammenfassung der behandelten Idiome.
Die Lösungen zu den Übungen findet ihr sowohl unten in den Beispielen als auch unter github.com/meshell/Cpp-Idioms.
C++ Idioms
A programming idiom is a recurring construct in a programming
language. It is important to know the idioms associated with a
programming language and how to use them for gaining fluency in that
language.
Idioms are similar to patterns but usually smaller, programming language specific and do cover algorithms and concepts rather than design issues.
RAII
Intent
To guarantee release of resource(s) at the end of a scope
To provide basic exception safety guarantee
Description
Resource Acquisition Is Initialization (RAII), is a C++ programming technique which binds the life cycle of a resource (allocated memory, open socket, open file, locked mutex, database connection—anything that exists in limited supply) to the lifetime of an object with automatic storage duration.
RAII guarantees that the resource is available to any function that may access the object (resource availability is a class invariant). It also guarantees that all resources are released when their controlling objects go out of scope, in reverse order of acquisition. Likewise, if resource acquisition fails (the constructor exits with an exception), all resources acquired by every fully-constructed member and base subobject are released in reverse order of initialization. This leverages the core language features (object lifetime, scope exit, order of initialization and stack unwinding) to eliminate resource leaks and guarantee exception safety. Another name for this technique is Scope-Bound Resource Management (SBRM).
Example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Avoid manual memory management to improve safety and reduce bugs and memory leaks.
Declare ownership explicitly
Description
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Item 18-22 of "Effective Modern C++" by Scott Meyers, O'Reilly, 2014
PIMPL
Intent
Remove compilation dependencies on internal class implementations and improve compile times.
Description
When anything in a header file class definition changes, all users of that class must be recompiled – even if the only change was to the private class members that the users of the class cannot even access.
The PIMPL idiom hides private members from any users of the header file, allowing these internal details to change without requiring recompilation of the client code.
Example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Item 22 of "Effective Modern C++" by Scott Meyers, O'Reilly, 2014
Rule of Five
Intent
Safely and efficiently implement RAII to encapsulate the management of dynamically allocated resources.
Description
The rule of five is a modern expansion of the rule of three. Firstly, the rule of three specifies that if a class implements any of the following functions, it should implement all of them:
copy constructor
copy assignment operator
destructor
These functions are usually required only when a class is manually managing a dynamically allocated resource, and so all of them must be implemented to manage the resource safely.
In addition, the rule of five identifies that it usually appropriate to also provide the following functions to allow for optimized copies from temporary objects:
move constructor
move assignment operator
Example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
To create an exception safe implementation of overloaded assignment operator.
Description
Copy assignment and move assignment operators can be expressed in terms of move constructor, destructor, and the swap() member function, if one is provided. For the move assignment operator this comes at the cost of one additional call to the move constructor , which is often acceptable.
Example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Utilise the value semantics of existing types to avoid having to implement custom copy and move operations.
Description
Classes that have custom destructors, copy/move constructors or copy/move assignment operators should deal exclusively with ownership and support the appropriate copy/move semantics. Other classes therefore should not have custom destructors, copy/move constructors or copy/move assignment operators.
Example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
When a base class is intended for polymorphic use, its destructor may have to be declared public and virtual. This blocks implicit moves (and deprecates implicit copies), and so the special member functions have to be declared as defaulted.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Synthesize a new type or types based on template argument(s)
Localize default policies when policy-based class design is used
Example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Override a virtual function of a base class in a safe manner.
Description
Overriding virtual functions may cause problems, for example during refactoring, when renaming a (non pure) virtual base method. Because the compiler cannot warn you that you forgot to replace the overridden methods in the specialized classes you may actually declare a new method in the specialized class instead of overriding one.
Therefore as a guideline when using C++11 or higher is:
Always write override when you intend to override a virtual function.
Example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Writing final makes a virtual function no longer overrideable in further-derived classes, or a class no longer permitted to have further-derived classes.
Example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Minimize the capacity of a container just enough to hold existing range.
Description
Since C++11 the Shrink-to-fit idiom is directly supported.
Example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Executes a for loop over a range of values, such as all elements in a container.
Description
Since C++11 the Range-based for loop is used as a more readable equivalent to the traditional for loop.
Example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Specify that the type of the variable that is being declared will be automatically deduced from its initializer.
Write code against interfaces, not implementations.
Prevent correctness and performance issues that can bedevil manual type declarations.
Description
When declaring variables in block scope, in namespace scope, in init statements of for loops, etc, the keyword auto may be used as the type specifier. Once the type of the initializer has been determined, the compiler determines the type that will replace the keyword auto using the rules for template argument deduction from a function call.
Examples
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Item 5 of "Effective Modern C++" by Scott Meyers, O'Reilly, 2014
Use Standard Library Algorithms
Intent
Use the standard library algorithms rather than reinventing the wheel.
Examples
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
To have an integral value that is const and known during compilation.
To place values in read-only memory.
Example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Item 15 of "Effective Modern C++" by Scott Meyers, O'Reilly, 2014
User-defined literals
Intent
Produce objects of user-defined type by defining a user-defined suffix.
Example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Creating objects in place while inserting into a container.
Enable insertion of elements that are not CopyConstructable.
Example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters