The term ‘Modern C++’ is used to describe the current best practices for the use of C++. In some cases, this may mean new capabilities of the language; in other cases it means more effective ways of performing familiar programming tasks.
This advanced course is designed to transition experienced C++ programmers to the latest incarnation of the C++ language. The focus is to teach good programming practice using Modern C++ and to put the latest features of the language into context.
The course covers C++11, C++14 and C++17 and where relevant refers to C++20.
Course objectives:
- To provide a deep understanding of the C++ programming language.
- To give you practical experience of writing Modern C++ on hosted embedded systems
- To give you the confidence to apply these new concepts to your next project.
Delegates will learn:
- Modern C++ syntax, semantics and library features
- The Application Binary Interface (ABI) and memory model of C++
- Idioms and patterns for building effective C++ programs
- Real-time and concurrency design issues
Pre-requisites:
- A good working knowledge of C++ (knowledge of C++11 onwards is useful, but not essential)
- Some experience of development multi-threaded applications is useful.
- A working understanding of machine architectures is helpful.
Who should attend:
- This course is aimed at C++ programmers who are using earlier standards of C++, and experienced C++ programmers who want to extend and expand their C++ skills.
Duration:
- Five days.
Course materials:
- Delegate manual
- Delegate workbook
Course workshop:
- Attendees perform hands-on exercises during course practicals. Approximately 50% of the course is given over to practical work. The tools used are indicative of current modern working practices in the embedded arena.
Part 1 - Core concepts
The C++ object model
- Declaration and definition
- Brace initialisation syntax
- ODR-use and 'The One Declaration Rule'
- Object scope and lifetime
- The C++ object (memory) model
Expressions
- Expressions,
- l-values and r-values
- statements,
- happens-before / happens-after
User defined types
- Aggregate types – structs
- Brace elision
- Classes
- Non-Static Data Member Initialisers
- Delegating constructors
- std::initializer_list
Functions
- Function call ABIs
- Input, Output and Input-Output parameters
- const correctness
- Copy elision
- Attributes
Type deduction
- Automatic type deduction
- Automatic function return-type deduction
- Structured bindings
- Using aliases
Constants
- Literals
- Const qualification
- Constexpr
- constexpr functions
- enum class
- enum underlying type
Connecting objects
- Unidirectional Associations
- Bidirectional association
- Forward declarations
Composition
- Nested object construction
Creating substitutable types
- Specialisation vs inheritance
- Substitution
- The Liskov Substitution principle
- The virtual function ABI
Abstract Base Classes
- The Single Responsibility principle
- Pure virtual functions
- Abstract types
- Dynamic cast
Realising interfaces
- The Dependency Inversion principle
- The Interface concept
- Pure virtual classes
- The Interface Segregation principle
Part 2 - STL containers
Sequence containers
- The problems with C-style arrays
- std::array
- Dynamic sequence containers
- Emplacement
Algorithms
- The iterator model
- Range-for
- Algorithms
Associative containers
- std::pair
- Sets and maps
- Hash-maps - std::unordered_map
Callable objects
- Lambda expressions
- The 'block-scoped function' concept
- Generic lambdas
- std::function
Variable types
- Generic structures – std::tuple
- Nullable types – std::optional
- Type-safe unions – std::variant
- The Visitor pattern
- Type-safe void pointers – std::any
Part 3 - Resource management
Resource management
- The resource lifetime problem
- Overloading the copy constructor
- Overloading the assignment operator
- The 'Rule of the Big Three'
- The copy-swap idiom
Move semantics
- The cost of copying
- 'Resource pilfering'
- Move constructors
- The Rule of Four and A Half
- Move assignment
- std::move
- Compiler overload provision for copy / swap
Smart pointers
- The problem with raw pointers for memory management
- std::unique_ptr
- std::shared_ptr
- std_weak_ptr
Part 4 - Templates
Template functions
- The problems with function-like macros
- Template functions
- Template parameter type deduction
- The forwarding reference idiom
- Template function overloading
Template classes
- Generic classes
- Template type deduction
- Template deduction guidelines
Templates and polymorphism
- The cost of virtual interfaces
- Policy patterns
Perfect forwarding
- Variadic templates
- std::forward
- std::forward vs std::move
Conditional coding
- Condition compilation with the pre-processor
- Template class explicit and partial specialisation
- Compile-time function selection (SFINAE)
- Compile-time implementation selection - constexpr-if
Part 5 - Concurrency
Threading
- Concurrency vs parallelism
- std::thread
- Run policies
- Polymorphic threads
- Waiting for threads to finish
- Detaching threads
Mutual exclusion
- Race conditions
- Mutual exclusion
- The scope-locked idiom
- std::lock_guard and std::unique_lock
Atomic types
- Shared objects in multiprocessor environments
- Why volatile is inappropriate
- Atomic types
- Load-acquire / Store-release barriers
- When atomic types are inadequate
Monitors
- Condition variables
- The Guarded Suspension pattern
Asynchronous tasks
- The Asynchronous Message pattern
- The Promise / Future pattern
- Packaged tasks
- std::async
- Throwing exceptions between threads
- Launch policies
Appendices
Appendix - User defined literals
- 'Rommable' types
- operator ""
Appendix - Exception handling
- Error handling strategies
- Throwing / catching exceptions
- Building an exception hierarchy
- Standard library exceptions
- Specifying your exception contract
Appendix - Regular expressions
- Regular expressions
- Regex syntax
- Searching using regexes
- Complete and partial matches
Appendix - Container memory allocators
- Reserving memory on a container
- The allocator interface
- Memory resources
- Polymorphic allocators
Appendix - The C++ build process
- The seven stages of compilation
- Object files
- Imports and Exports tables
- Linkage
- ELF files
- Object conversion for embedded systems