Skip to content

Instantly share code, notes, and snippets.

@jreuben11 jreuben11/C++_quickref.md
Last active Apr 11, 2018

Embed
What would you like to do?
C++11 in a nutshell

C++11 in a nutshell

Modern C++ Coding Style

This post is based upon the standard - not supported with VC compiler ! Try these techniques using GCC / LLVM compilers and QtCreator / CLion IDEs

Avoid C programming style idioms

  • = rather than strcpy() for copying , == rather than strcmp() for comparing
  • use const , constexpr functions rather than #DEFINE, macros
  • Avoid void*, union, and raw casts (use static_cast instead)
  • use std:string instead of char*
  • avoid pointer arithmetic
  • To obey C linkage conventions, a C++ function must be declared to have C linkage

Avoid C# / Java programming style idioms

  • Minimize the use of reference and pointer variables: use local and member variables
  • Use abstract classes as interfaces to class hierarchies; avoid “brittle base classes,” that is, base classes with data members.
  • Use scoped resource management (“Resource Acquisition Is Initialization”; RAII)
  • Use constructors to establish class invariants (and throw an exception if it can’t)
  • Avoid “naked” new and delete; instead, use containers (e.g., vector, string, and map) and handle classes (e.g., lock and unique_ptr).
  • minimal run-time reflection: dynamic_cast and typeid
  • Namespaces are non-modular - headers can introduce name clashes - avoid using directives in header files, because it increases the chances of name clashes

C++11 new features

  • Constructor Controls =delete and =default
  • type deduction - auto
  • constant expression compile time evaluation - constexpr
  • In-class member initializers
  • Inheriting constructors
struct derived : base {
   using base::base; // instead of deriving multiple constructor sigs
};
  • Lambda expressions
  • Move semantics
  • specify function may not throw exceptions - noexcept
  • A proper name for the null pointer - nullptr (instead of NULL)
  • The range-for statement
  • Override controls: final and override
  • Template Type aliases - binding arguments of another template
template<class T> struct Alloc {};
template<class T> using Vec = vector<T, Alloc<T>>;
// type-id is vector<T, Alloc<T>>
Vec<int> v; // Vec<int> is the same as vector<int, Alloc<int>>
  • Typed and scoped enumerations: enum class
  • Universal and uniform initialization
  • Variadic templates
  • Hashed containers, such as unordered_map
  • basic concurrency library components: thread, mutex, and lock
  • asynchronous computation: future, promise, and async()
  • regexp
  • unique_ptr, shared_ptr
  • tuple
  • bind(), function
  • decltype(expr) - reuse a type

Basics

The stream idiom

  • overloading IO stream ops:
ostream& operator<<(ostream& os, const Entry& e)
istream& operator>>(istream& is, Entry& e)
  • cout << , cin >> - stdio streams
  • getline() - helper function for making it easier to read from stdin
  • If a pointer to function is given as the second argument to <<, the function pointed to is called. cout<<pf means pf(cout). Such a function is called a manipulator
  • <sstream> istringstream - A stream that reads from a string
  • c_str() returns a C-style pointer to a zero-terminated array of characters

determine the memory footprint of a variable, or the size of an array

sizeof(T)
extent <decltype( T )> ::value
  • size of an array must be a constant expression

Utilize initializer lists, auto, constexpr

  • use initializer lists {} instead of =, () - prevents narrowing conversions
  • with auto, need to use =
  • prefer constexpr to const - compile time evaluation

iterating over a container:

  • v.begin() and v.end() or begin(v) and end(v)
  • for (const auto& x : v) - for each x in v
  • for (int& x : v) - to modify an element in a range-for loop, the element variable should be a reference

Mechanisms: pass by ref, const functions, operator overloading, subscripting

  • pass by ref
void doSomething(MyClass& c) {}
  • const function:
double real() const { return re; }
  • operator overload: add to re and im
complex& operator+=(complex z) {
  re+=z.re, im+=z.im;
  return * this;
}
  • element access: subscripting
double& operator[](int i) { return elem[i]; }

A common pattern: templatized RAII Handles as custom container wrappers

template<typename T>
class Handle {          // Parameterized Type
  private:
    T* elem;
...
Handle(int s) :elem{new double[s]}, sz{s}  { ... } // constructor: acquire resources, initializer_list<T>
~Handle() { delete[] elem; }                       // destructor: release resources
virtual double& operator[](int) = 0;     // pure virtual function
void doSomething(vector<Item*>& v, int x) { //  do something to all items
  for (auto p : v)
    p–>doSomething(x);
}

Optimal techniques to pass arguments and retvals

  • pass & return references & from functions.
  • never return a pointer *. can return a smart pointer.
  • Return containers by value (relying on move for efficiency)
  • Each time a function is called, a new copy of its arguments is created.
  • a pointer or a reference to a local non-static variable should never be returned.
  • non-primitive arguments should be passed as const &
  • For template arguments, an rvalue reference is used for “perfect forwarding”
  • Default arguments may be provided for trailing arguments only
  • the recommended way to pass containers in and out of functions: pass Containers by reference, return them as objects by value (implicitly uses move)

range-for over a handle

  • To support the range-for loop for a container handle, must define suitable begin() and end() functions:
template<typename T>
T* begin(Handle<T>& x)
{}

functors, lambdas, variadic templates

  • functor: call operator
bool operator()(const T& x) const { return x<val; }
  • bind - forward call wrapper
  • lambda - eg capture all by ref
[&](const string& a){ return a<s; }
  • variadic template
template<typename T, typename... Tail>
void f(T head, Tail... tail)

ISO C++ standard types

  • character types: char (8), [signed | unsigned ] char, wchar_t (unicode), char16_t (UTF), char32_t. L'AB'
  • <cctype>:: - isspace(), isalpha(), isdigit(), isalnum()
  • integer types: [signed | unsigned] short | int | long | long long
  • ::size_t x = sizeof(xxx) ; - implementation defined type
  • query arithmetic type properties: <limits>::numeric_limits

initialization gotchas – narrowing, default values, initialization lists

  • error: narrowing bool b2 {7};
  • {} indicates default value (nullptr for pointers)
  • if (p) { - equivalent to p != nullptr
  • auto - use =, because {} is deduced to std::initializer_list<T>
  • The only really good case for an uninitialized variable is a large input buffer.
  • only stack variables are default initialized !

function pointers

  • pointer to function taking a double and returning an int:
    using PF = int( * )(double);  
  • beware: cannot dereference or increment void*
void (* pf)(string)  = &DoSomething;
pf("blah");
using F = void( * )(string);

problems with passing arrays as arguments

  • arrays cannot be copied, assigned, or passed by val
  • from <string.h> - the size of the array is lost to the called function: extern "C" int strlen(const char *);
  • an argument of type T[] will be converted to a T* by val - preferable to pass a reference to some container

Prefer references

  • must be initialized from an object / primitive, read only, object like syntax, used for passing by ref params / retvals
int var = 0;
int& rr {var};
++rr;               // var is incremented by 1
int* pp = &rr;      // pp points to var
  • move uses “ref ref”: move(x) means static_cast<X&&>(x) where X& is the type of x.

Simple constructs:

  • struct, union, enum, enum class
  • enum class vs enum
enum class Color { red, blue, green };  
auto col = Color::red;   
  • struct vs class - struct can be initialized using the {} notation - order is important , no need for constructor. all members public.

function signature keywords

[[noreturn]] virtual inline auto f(const unsigned long int *const) –> void const noexcept;
  • avoid argument conversions for params: explicit - prevent implicit conversions
  • 2 ways to specify an inline function: A) A member function defined within the class declaration is taken to be an inline member function. B) Use inline keyword
  • declare a static function - keyword static in declaration is not repeated in the definition eg
template<class T, class U>
auto product(const vector<T>& x, const vector<U>& y) –> decltype(x*y);

What makes a function signature unique

  • unique function signature check ignores const in params
  • Function argument names are not part of the function type
  • an argument is unused in a function definition by not naming it

Error handling

gracefully / ungracefully halting execution

  • if (something_wrong) exit(1);
  • terminate() - does not invoke destructors. calls abort()
  • std::set_terminate()
  • quick_exit() , at_quick_exit()

basic guarantee vs strong guarantee

  • basic guarantee for all ops: invariants of all objects are maintained, and no resources are leaked
  • strong guarantee for key ops: either the operation succeeds, or it has no effect
  • nothrow guarantee for some operations

handling errors

  • errno vs <stdexcept>
  • throw ex
  • throw; - rethrow
  • catch (std::exception& err) {
  • catch (...)

Catch common exceptions in main

catch (...) {
  cerr << "x"
}

the standard exception hierarchy

  • exception: logic_error, runtime_error, bad_exception, bad_alloc, bad_cast, bad_typeid
  • logic_error: length_error, domain_error, invalid_argument, out_of_range, future_error
  • runtime_error: overflow_error, range_error, underflow_error, system_error, regex_error, ios_base::failure

useful members of the exception class

  • exception::what()
  • current_exception()
  • rethrow_exception()
  • make_exception_ptr()
  • exception_ptr
  • nested_exception
  • terminate()

best practices for handling exceptions

  • catch exception&
  • destructors do not throw
  • can throw runtime_error in ctor
  • an exception is potentially copied several times up the stack before it is caught - don’t put huge amounts of data in exception body
  • innocent-looking operations (such as <, =, and sort()) might throw exceptions
  • error in a thread can crash a whole program - add a catch-all handler to main()
  • The body of a function can be a try-block.
  • handle RAII is neater than try catch finally

assertions

  • compile-time static_assert vs runtime macro <cassert> assert

handling exceptions in multithreaded code

  • packaged_task does the following:
catch(...) { myPromise.set_exception(current_exception()); }

Source Files and Programs

the C++ compilation and linkage process

  • A program is a collection of separately compiled units combined by a linker
  • file is unit of compilation
  • precompiler --> translation unit
  • A program must contain exactly one function called main()
  • An entity must be defined exactly once in a program. It may be declared many times, but the types must agree exactly.
  • Outside a class body, an entity must be declared before it is used
  • static vs shared libraries

include semantics

  • #include <iostream> - from standard include directory
  • #include "myheader.h" - from current directory

external linkage

  • external linkage - when definition is not in same TU as declaration, use extern for external linkage
#ifdef __cplusplus
extern "C" {}   // a linkage block
#endif
  • using, constexpr, static & const not accessible from other TUs - hence extern const

Defining macros

#define PRINT(a,b) cout<<(a)<<(b)
  • concatenate: Writing #x " = " rather than #x << " = " is obscure “clever code”
  • predefined macros: __FUNC__ , __FILE__ , __LINE__

best practices for reducing compile time

  • Precompiled headers - modern C++ implementations provide precompiling of header files to minimize repeated compilation of the same header.
  • avoid global variables
  • a header should never contain: ordinary function definitions, fields, global variables, unnamed namespaces, using directives
  • To ensure consistency (identical definition), place using x= aliases, consts, constexprs, and inlines in header files
  • dont abuse #include
  • minimize dependencies
  • compiler include guards
  • An unnamed namespace {} can be used to make names local to a compilation unit - internal linkage

Classes and OOP

class default methods

  • by default a class provides 6 default methods
class X {
  X();                     // default constructor
  X(const X&);             // copy constructor
  X(X&&);                  // move constructor
  X& operator=(const X&);  // copy assignment: clean up target and copy
  X& operator=(X&&);       // move assignment: clean up target and move
  ~X();                    // destructor: clean up
}
X x = new X();

When to customise the default functions of a class:

  • If a class has a virtual function, it needs a virtual destructor
  • If a class has a reference member, it probably needs copy operations
  • If a class is a resource handle, it probably needs copy and move operations, constructor, a destructor, and non-default copy operations
  • If a class has a pointer member, it probably needs a destructor and non-default copy operations
  • Don't need a copy constructor just to copy an object - objects can by default be copied by assignment. default semantics is memberwise copy.

default and delete functions

  • =default and =delete
  • if you implement custom class, for default functions that are default, specify =default;
  • prevent destruction of an object by declaring its destructor =delete (or private)
  • prevent slicing - Prohibit copying of the base class: delete the copy operations.

constructor call order:

  • be aware that constructor is called on every copy and move
  • delegating constructor - when one constructor calls another
  • Constructors execute member and base constructors in declaration order (not the order of initializers)
  • A constructor can initialize members and bases of its class, but not members or bases of its members or bases
  • Prevent conversion of a pointer-to-a-derived to a pointer-to-a-base: make the base class a protected base

Defining a class

  • constructor initialization lists
  • const functions and mutable fields
  • friend class / functions
  • defining an abstract base class
  • abstract base class definition (.cpp): virtual ~Base() = 0;

Nested Classes

  • A nested class has access to non-static members of its enclosing class, even to private members (just as a member function has), but has no notion of a current object of the enclosing class.
  • A class does not have any special access rights to the members of its nested class

different types of initialization: default, copy, memberwise

  • default initialization MyClass o1 {};
  • memberwise initialization MyClass o2 {"aaa", 77 };
  • copy initialization MyClass o3 { o2 };

Operator Overloading

  • stream out operator:
ostream& operator<<(ostream&, const string&);
  • calling std::cout << s; is the same as operator<<(std::cout, s);
  • overload the + and += operators for a Complex number type:
complex operator+(complex a, complex b) {
  return a += b; // access representation through +=.  
  // note: arguments passed by value, so a+b does not modify its operands.

inline complex& complex::operator+=(complex a) {
  re += a.re;
  im += a.im;
  return * this;
}
  • define a conversion operator: (resembles a constructor)
MyClass::operator int() const { return i; }      
  • declaring an indexer
const MyClass& operator[] (const int&) const;
  • declaring a functor:
int operator()(int);
pair<int,int> operator()(int,int);
  • smart pointers overload operator –>, new
  • increment / decrement operators:
Ptr& operator++();             // prefix
Ptr operator++(int);           // postfix
Ptr& operator––();             // prefix
Ptr operator––(int);           // postfix
  • allocator / deallocator operators - implicitly static
void* operator new(size_t);               // use for individual object
void* operator new[](size_t);             // use for array
void operator delete(void*, size_t);      // use for individual object
void operator delete[](void*, size_t);    // use for array
  • user defined literal operator:
constexpr complex<double> operator"" i(long double d) ;

the order of construction / destruction in a class hierarchy

  • Objects are constructed from the base up and destroyed top-down from derived
  • destructors in a hierarchy need to be virtual
  • the constructor of every virtual base is invoked (implicitly or explicitly) from the constructor for the complete object
  • destructors are simply invoked in reverse order of construction - a destructor for a virtual base is invoked exactly once.

keywords virtual, override, final:

  • keywords virtual, override, final should only appear in .h files
  • override and final are compiler hints
  • override specifier comes last in a declaration.
  • virtual functions - vtbl efficiency within 75%
  • final - can make every virtual member function of a class final - add final after the class name
class Derived final : public Base {

Scope rules for deriving from a base class

  • deriving from a base class can be declared private, protected, or public
  • If B is a private base, its public and protected members can be used only by member functions and friends of D. Only friends and members of D can convert a D* to a B*
  • If B is a protected base, its public and protected members can be used only by member functions and friends of D and by member functions and friends of classes derived from D. Only friends and members of D and friends and members of classes derived from D can convert a D* to a B*.
  • If B is a public base, its public members can be used by any function. In addition, its protected members can be used by members and friends of D and members and friends of classes derived from D. Any function can convert a D* to a B*.

Best practices for abstract classes and virtual functions

  • An abstract class should have a virtual destructor
  • A class with a virtual function should have a virtual destructor;
  • An abstract class typically doesn’t need a constructor

Best practices for declaring interfaces and data members

  • Prefer public members for interfaces;
  • Use protected members only carefully when really needed; a protected interface should contain only functions, types, and constants.
  • Don’t declare data members protected; Data members are better kept private & in the derived classes to match specific requirements.

Best practices deriving from a base class

  • Don’t call virtual functions during construction or destruction
  • Copy constructors of classes in a hierarchy should be used with care (if at all) to avoid slicing
  • A derived class can override new_expr() and/or clone() to return an object of its own type
  • covariant return rule - Return Type Relaxation applies only to return types that are pointers or references
  • a change in the size of a base class requires a recompilation of all derived classes

Almost Reflection

RTTI

  • <typeinfo> type_info typeid(x)
  • typ_info.name()
  • size_t typ_info.hash_code()

type traits to inspect code elements

  • <type_traits>
  • eg is_class<X> , is_integral<X>
  • eg
static_assert(std::is_floating_point<T>::value ,"FP type expected");
  • Add_pointer<T>
  • enable_if and conditional,
  • declval<X>

Casting

different types of casts:

  • const_cast for getting write access to something declared const
  • static_cast for reversing a well-defined implicit conversion
  • reinterpret_cast for changing the meaning of bit patterns
  • dynamic_cast - is run-time checked - it supports polymorphic class hierarchies

limits of dynamic casting

  • dynamic_cast used an upcast - returns nullptr otherwise.
if (auto px = dynamic_cast<MyClass*>(py)){}
  • dont use a ref: dynamic_cast<MyClass&> - could throw a bad_cast
  • dynamic_cast cannot cast from a void*. For that, a static_cast is needed
  • crosscasting, dynamic dispatch. better to use visitor pattern

upcasting vs downcasting

class Manager : public Employee {}

void g(Manager mm, Employee ee) {
  Employee* pe = &mm;               // OK: every Manager is an Employee
  Manager* pm = &ee;                // error: not every Employee is a Manager
  pm–>level = 2;                    // error: ee doesn't have a level
  pm = static_cast<Manager*>(pe);   // brute force: works
}

void Manager::doSomething() const {
  Employee:: doSomething();      //       base method
  doSomething();                // error
}

Custom Allocators

  • explicitly calling new: placement new - edge case where we specify memory address
void C::push_back(const X& a){
  new(p) X{a};   //  copy construct an X with the value a in address p
}
void C::pop_back() {
  p–>~X();      // destroy the X in address p
}

explicitly overloading allocators / deallocators

  • explicit:
  • new(&s) string{"xxx"}; - placement new: explicitly construct string
  • s.~string(); - explicitly destroy string
  • for enum class, define operator|() , operator&()
  • allocator<T>

Templates

Advantages of Templates

  • faster & easier to inline - no casting, or double dispatch
  • code for a member function of a class template is only generated if that member is used
  • Use templates to express containers
  • excellent opportunities for inlining, pass constant values as arguments --> compile-time computation.
  • resembles dynamic programming with zero runtime cost

Limitations of templates

  • no way to specify generic constraints ... until concepts. so errors that relate to the use of template parameters cannot be detected until the template is used
  • A member template cannot be virtual
  • copy constructors, copy assignments, move constructors, and move assignments must be defined as non-template operators or the default versions will be generated.
  • A virtual function member cannot be a template member function
  • Source code organization: #include the .cpp definition of the templates in every relevant translation unit --> long compile times
  • caution is recommended when mixing object-oriented and generic techniques - can lead to massive code bloat for virtual functions

creating and using a template

template<typename C>
class MyClass { };

MyClass<string> o;      // called a specialization
  • Members of a template class are themselves templates parameterized by the parameters of their template class.
template<typename C>
MyClass<C>::MyClass() {}        // ctor

template compile-time polymorphism

template<typename T>
void sort(vector<T>&);          // declaration
void f(vector<int>& vi, vector<string>& vs) {
  sort(vi);  // sort(vector<int>&);
  sort(vs);  // sort(vector<string>&);
}

Function Template Arguments

  • Use function templates to deduce class template argument types
template<typename T, int max>
struct MyClass {};

template<typename T, int max>
void f1(MyClass<T,int>& o);

void f2(MyClass<string,128>& o){
  f1(o);      // compiler deduces type and non-type arguments from a call,
}
  • function template overloads
sqrt(2);     // sqrt<int>(int)
sqrt(2.0);   // sqrt(double)
sqrt(z);     // sqrt<double>(complex<double>)

SFINAE

  • A template substitution failure is not an error. It simply causes the template to be ignored;
  • use enable_if to conditionally remove functions from overload resolution

Template Aliases

  using IntVector = vector<int>;

Best practices for implementing Templates

  • If a class template should be copyable, give it a non-template copy constructor and a non-template copy assignment - likewise for move
  • Avoid nested types in templates unless they genuinely rely on every template parameter
  • Define a type as a member of a template only if it depends on all the class template’s arguments
  • lifting - design for multiple type arguments

Concepts Generic Constraints

  • Estd namespace – template constraints
  • Ordered<X>, Equality_comparable<T>, Destructible<T>, Copy_assignable<T>, etc
  • implement a concept as a constexpr templated function with static_assert
  • parameterized --> constraint checks

Passing parameters to templates

  • template Parameters can be template types, built in types, values, or other class templates!
  • literal types cannot be used as template value parameters; function templates cannot be used as template params
  • can specify default types !
template<typename Target =string, typename Source =string>
Target to(Source arg)       // convert Source to Target
{ ... }

auto x1 = to<string, double>(1.2);  // very explicit (and verbose)
auto x2 = to<string>(1.2);         // Source is deduced to double
auto x3 = to<>(1.2);               // Target is defaulted to string; Source is deduced to double
auto x4 = to(1.2);                 // the <> is redundant

partial specialization vs complete specialization

  • complete specialization - Specialize templates to optimize for important cases
  • partial specialization -> curbing code bloat - replicated code can cost megabytes of code space, so cut compile and link times dramatically
  • to declare a pointer to some templated class, the actual definition of a class is not needed:
        X* p;    // OK: no definition of X needed
  • one explicit instantiation for a specialization then use extern templates for its use in other TUs.

template<> argument deduction

  • template<> argument can be deduced from the function argument list, we need not specify it explicitly:
template<>
bool less(const char* a, const char* b)

The curiously recurring template pattern (CRTP)

  • a class X derives from a class template instantiation using X itself as template argument
template<class T>
class Base {
  // methods within Base can use template to access members of Derived
};

class Derived : public Base<Derived> { };
  • use for static polymorphism (generic meta-programming )

Template Metaprogramming

  • templates constitute a complete compile-time functional programming language
  • constexpr
  • it is achieved via type functions, iterator traits
  • is_polymorphic<T>
  • Conditional<(sizeof(int)>4),X,Y>{}(7); - make an X or a Y and call it
  • Scoped<T>, On_heap<T>
  • template<typename T>
  • using Holder = typename Obj_holder<T>::type;
  • is_pod<T>::value
  • iterator_traits
  • <type_traits>
  • Enable_if<Is_class<T>(),T>* operator–>(); - select a member (for classes only)
  • std::is_integral and std::is_floating_point

variadic templates

template<typename T, typename... Args>  // variadic template argument list: one or more arguments
void printf(const char* s, T value, Args... args)    // function argument list: two or more arguments
  • One of the major uses of variadic templates is forwarding from one function to another
  • pass-by-rvalue-reference of a deduced template argument type “forward the zero or more arguments from t.”
template<typename F, typename... T>
void call(F&& f, T&&... t) {
  f(forward<T>(t)...);
}
auto t = make_tuple("Hello tuple", 43, 3.15);
double d = get<2>(t);

Know the Standard-Library

  • <utility> operators & pairs
  • <tuple>
  • <type_traits>
  • <typeindex> use a type_info as a key or hashcode
  • <functional> function objects
  • <memory> resource management pointers
  • <scoped_allocator>
  • <ratio> compile time rational arithmetic
  • <chrono> time utilities
  • <iterator> begin, end
  • <algorithm>
  • <cstdlib> - bsearch(), qsort()
  • <exception> - exception class
  • <stdexcept> - standard exceptions
  • <cassert> - assert macro
  • <cerrno> C style error handling
  • <system_error> - system error support: error_code, error_category, system_error
  • <string> - strlen(), strcpy(),
  • <cctype> - character classification: atof() , atoi()
  • <cwctype> wide character classification
  • <cstring> C-style string functions
  • <cwchar> C-style wide char functions
  • <cstdlib> C-style alloc functions
  • <cuchar> C-style multibyte chars
  • <regex>
  • <iosfwd> forward declarations of IO facilities
  • <iostream>
  • <ios> - iostream bases
  • <streambuf> - stream buffers
  • <istream> - input stream template
  • <ostream> - output stream template
  • <iomanip> - Manipulator
  • <sstream> - streams to/from strings
  • <cctype> - char classification functions
  • <fstream> - streams to/from files
  • <cstdio> - printf family of IO
  • <cwchar> - printf family of IO for wide chars
  • <locale> - cultures
  • <clocale> - cultures C-style
  • <codecvt> - code conversion facets
  • <limits> - numerical limits
  • <climits> - C-style integral limits
  • <cfloat> - C-style float limits
  • <cstdint> - standard integer type names
  • <new> - dynamic memory management
  • <typeinfo> - RTTI
  • <exception>
  • <initializer_list>
  • <cstddef> - C-style language support sizeof(), size_t, ptrdiff_t, NULL
  • <cstdarg> - variable length function args
  • <csetjmp> - C-style stack unwinding: setjmp , longjmp
  • <cstdlib> - program termination , C-style math functions eg abs() , div()
  • <ctime> - system clock
  • <csignal> - C-style signal handling
  • <complex>
  • <valarray>
  • <numeric>
  • <cmath>
  • <random>
  • <atomic>
  • <condition_variable>
  • <future>
  • <mutex>
  • <thread>
  • <cinttypes> type aliases for integrals
  • <cstdbool> C _Bool, true, false
  • <ccomplex>
  • <cfenv> C floating point stuff
  • <ctgmath>

STL Containers

STL features:

  • concepts: sequence vs associative containers; adapters, iterators, algorithms, allocators
  • container adapters - eg stack, queue, deque - double ended queue
  • Iterators are a type of pointer used to separate algorithms and containers
  • reverse iterators: rbegin, rend
  • const iterators: cbegin, cend
  • push_back does a copy via back_inserter
  • forward_list - SLL
  • multiset / multimap - values can occur multiple times
  • unordered_X
  • Xstream_iterator
  • How to implement a range check vector – not sure if this is good idea …
override operator [] with at()
  • prefer standard algorithms over handwritten loops
  • accumulate - aggregator algo
  • valarray - matrix slicing
  • unordered_map / set; multimap / set
  • bitset - array of bool
  • pair<T,U> , tuple<W,X,Y,Z>

functions common to several containers:

  • less<T>
  • copy(), find(), sort(), merge(), cmp(), equiv(), swap() , binary_search(), splice()
  • size(), capacity()
  • at() - range checks
  • emplace - nice and terse move push_back
  • hash<T> - functor
  • efficiently moving items from one container to another
copy(c1,make_move_iterator(back_inserter(c2)));    // move strings from c1 into c2

Container and Algorithm requirements

  • To be an element type for a STL container, a type must provide copy or move operations;
  • arguments to STL algorithms are iterators, not containers
  • _if suffix is often used to indicate that an algorithm takes a predicate as an additional argument.

STL common algorithms:

  • lower_bound(), upper_bound(), iter_swap()
  • for_each(b,e,f)
  • sequence predicates: all_of(b,e,f) , any_of(b,e,f) , none_of(b,e,f)
  • count(b,e,v) , count_if(b,e,v,f)
  • isspace()
  • find_if(b,e,f)
  • equal(b,e,b2)
  • pair(p1,p2) = mismatch(b,e,b2)
  • search(b,e,b2,e2) - find a subsequence
  • transform(b,e,out,f)
  • copy(b,e,out), move(b,e,out)
  • copy_if(b,e,out,f)
  • unique, unique_copy
  • remove() and replace()
  • reverse()
  • rotate(), random_shuffle(), and partition() - separates into 2 parts
  • next_permutation(), prev_permutation() , is_permutation() - generate permutations of a sequence
  • fill(), generate_n(), uninitialized_copy, uninitialized_fill - assigning to and initializing elements of a sequence. (unitialized_ is for low level objects that are not initialized)
  • swap(), swap_ranges(), iter_swap()
  • sort(), stable_sort() - maintain order of equal elements, partial_sort()
  • binary_search() - search sequence that is pre-sorted
  • merge() - combine 2 pre-sorted sequences
  • set_union, set_intersection, set_difference
  • lexicographical_compare() - order words in dictionaries
  • min & max
  • Use for_each() and transform() only when there is no more-specific algorithm for a task

Iterating over a container

  • [b:e)
  • end points to the one-beyond-the-last element of the sequence.
  • Never read from or write to *end.
  • the empty sequence has begin==end;
while (b!=e) {       // use != rather than <
  // do something
  ++b;   // go to next element
}

Iterator operations

  • input (++ , read istream), output (++, write ostream), forward (++ rw), bidirectional(++, --), random access
  • iterator_traits - select among algorithms based on the type of an iterator
  • ++p is likely to be more efficient than p++.
  • 3 insert iterators:
  • insert_iterator - inserts before the element pointed to using insert().
  • front_insert_iterator - inserts before the first element of a sequence using push_front().
  • back_insert_iterator - inserts after the last element of the sequence using push_back().
  • Use base() to extract an iterator from a reverse_iterator

comparisons

  • T[N] vs array<T,N> (raw array vs array type) - Use array where you need a sequence with a constexpr size. Prefer array over built-in arrays
  • bitset<N> vs vector<bool> - Use bitset if you need N bits and N is not necessarily the number of bits in a built-in integer type. Avoid vector<bool>
  • pair<T,U> vs tuple<T...> - use make_pair() / make_tuple() for type deduction. tie() can be used to extract elements from a tuple as out params
  • basic_string<C>, valarray<T>

New Techniques: Lambdas, smart pointers and move

Mitigating common memory management problems

  • mem management problems: leaks, premature deletion, double deletion
  • int* p2 = p1; - potential trouble
  • handles, RAII, move semantics eliminate problems

function adapters

  • <functional> - function adaptors - take a function as argument and return a functor that can be used to invoke it
  • bind(f,args) , mem_fn(f) , not(f) - currying, partial evaluation. more easily expressed using lambdas. Uses _1 from std::placeholders
  • ref() - like bind(), but doesnt dereference early - use to pass references as arguments to threads because thread constructors are variadic templates. useful for callbacks, for passing operations as arguments, etc.
  • mem_fn() (or a lambda) can be used to convert the p–>f(a) calling convention into f(p,a)
  • function is specified with a specific return type and a specific argument type. Use function when you need a variable that can hold a variety of callable objects
int f(double);
function<int(double)> fct {f};  // initialize to f
fct = [](double d) { return round(d); };     // assign lambda to fct

Passing values in / out of Lambdas

  • lambda default is all by reference: [&]
  • [=] by value (copy). recommended for passing a lambda to another thread
  • mutable - capture values can change
  • for_each - just use ranged for
  • [&v...] variadic params can be captured
  • can capture the current object BY REFERENCE [this]
  • the minimal lambda expression is []{}
auto z4 = [=,y]()–>int { if (y) return 1; else return 2; }    // OK: explicit return type

Passing lambdas around

  • std::function<R(AL)> where R is the lambda’s return type and AL is its argument list of types - function<void(char* b, char* e)>
  • can store a lambda in a variable of type auto - no two lambdas have the same type

3 types of smart pointers in C++11

  • unique_ptr - note: there is no make_unique ... yet:
unique_ptr<X> sp {new X};

unique_ptr<int> f(unique_ptr<int> p) {
  ++ * p;
  return p;
}

void f2(const unique_ptr<int>& p) {
  ++ * p;
}

unique_ptr<int> p {new int{7}};
p=f(p);            // error: no copy constructor
p=f(move(p));      // transfer ownership there and back
f2(p);             // pass a reference
  • shared_ptr – create with make_shared() - eg a structure with two pointers: one to the object and one to the use count:
auto p = make_shared<MyStruct>(1,"Ankh Morpork",4.65);
  • weak_ptr - break loops in circular shared data structures
  • note: shared_ptr are copied , unique_ptr are moved
  • you obviously still need to know your pointer prefix operator overloads * , & :prefix unary * means “dereferenced contents of” and prefix unary & means “address of.”
  • Mixing containers and smart pointers: vector<unique_ptr<Item>> v; -rather than vector<Item*> or vector<Item>, because all items implicitly destroyed

move

  • STL containers & smart pointers leverage move operations, as should custom RAII handles: template<class T> class Handle { }
  • primitive types & their pointers are always copied, even when moved
  • move must leave the source object in a valid but unspecified state so its destructor can be called
  • a move cannot throw, whereas a copy might (because it may need to acquire a resource).
  • a move is often more efficient than a copy.
  • Because initializer_list elements are immutable, cannot apply a move constructor - use uninitialized_copy

copying vs moving

  • the diff between lvalues and rvalues: lvalue - named & unmovable VS rvalue - temporary value that is movable
  • copy constructors by default do memberwise copy - not good for containers !
  • A copy constructor and a copy assignment for a class X are typically declared to take an argument of type const X&
Item a2 {a1};                // copy initialization
Item a3 = a2;                // copy assignment
Handle(const Handle& a);             // copy constructor
Handle& operator=(const Handle  a);  // copy assignment
Handle(Handle&& a);               // move constructor
Handle& operator=(Handle&& a);          // move assignment
std::move(x)                    // explicit
=delete;        // supress default copy / move definitions

move vs forward

  • A move() is simply a cast to an rvalue: static_cast<Remove_reference<T>&&>(t);
  • forward() is for “perfect forwarding” of an argument from one function to another
  • <utility> swap()
  • <typeindex> comparing and hashing type_index (created from a type_info)

allocate / deallocate functions

  • p=a.allocate(n); - acquire space for n objects of type T
  • a.deallocate(p,n); - release space for n objects of type T pointed to by p

best practices for working with smart pointers

  • unique_ptr cannot be copied, but can be moved. When destroyed, its deleter is called to destroy the owned object.
  • Shared pointers in a multi-threaded environment can be expensive (because of the need to prevent data races on the use count).
  • A destructor for a shared object does not execute at a predictable time
  • Prefer resource handles with specific semantics to smart pointers
  • Prefer unique_ptr to shared_ptr.
  • Prefer ordinary scoped objects to objects on the heap owned by a unique_ptr
  • Minimize the use of weak_ptr
  • a weak_ptr can be converted to a shared_ptr using the member function lock():
if (auto q = p.lock()) {
} else {
  p.reset();
}

Basic Mathematics Support

query numeric limits

  • specializations of the numeric_limits template presented in <limits>
  • numeric_limits<unsigned char>::max()
  • <climits> - DBL_MAX and FLT_MAX C Macros

valarray efficient matrix operations

  • valarray - slices and strides for matrices
  • slice_array, gslice_array, mask_array, indirect_array
valarray<int> v {
  {00,01,02,03},    // row 0
  {10,11,12,13},    // row 1
  {20,21,22,23}     // row 2
};
  • slice{0,4,1} describes the first row of v (row 0)
  • slice{0,3,4} describes the first column (column 0)
  • gslice is a “generalized slice” that contains (almost) the information from n slices
  • accumulate() adds elements of a sequence using their + operator:
  • inner_product(), partial_sum() and adjacent_difference()
  • iota(b,e,n) assigns n+i to the ith element of [b:e).

generate random numbers

  • <random> - random_device, Rand_int , Rand_double
auto gen = bind(normal_distribution<double>{15,4.0},default_random_engine{});
for (int i=0; i<500; ++i) cout << gen();

Concurrency

different levels of concurrency and locking

  • atomic, thread, condition_variable, mutex , future + promise, packaged_task, and async()

Creating a worker thread

  • thread t {F{x}}; - pass a functor constructor to a thread --> thread executes functor
  • function arguments - const refs for RO, pointers for out params

Advanced Threading Constructs in C++11

  • advanced locking: defer_lock & explicit lock()
  • condition_variable - ::wait(), ::notify_one()
  • promise<T>::set_value(), future<T>::get
  • packaged_task<Task_Type> ::get_future()
  • async::get
  • thread_local

creating a critical section

mutex m; // used to protect access to shared data
void f() {
  unique_lock<mutex> lck {m}; // acquire the mutex m, automatically scoped
  // ... manipulate shared data ...
}

atomics

  • simplest memory order is sequentially consistent
  • Atomics - Lock-free programming: load and store
enum memory_order {
  memory_order_relaxed,
  memory_order_consume,
  memory_order_acquire,
  memory_order_release,
  memory_order_acq_rel,
  memory_order_seq_cst
};

r1 = y.load(memory_order_relaxed);
x.store(r1,memory_order_relaxed);
  • [[carries_dependency]] - for transmitting memory order dependencies across function calls
  • kill_dependency() - for stopping the propagation of such dependencies.
  • atomic<T> - compare_exchange_weak(), compare_exchange_strong(), is_lock_free()
  • 2 possible values of an atomic_flag are called set and clear.
  • atomic_thread_fence, atomic_signal_fence - barriers
  • volatile

simple multi-threaded programming

  • thread::join, joinable, swap, detach
thread my_thread2 {my_task,ref(v)};       // OK: pass v by reference

this_thread::sleep_until(tp);
this_thread::sleep_for(d);
this_thread::sleep_for(milliseconds{10});
this_thread::yield();
  • thread_local - thread local storage
  • thread::hardware_concurrency() - reports the number of tasks that can simultaneously proceed with hardware support
  • thread::get_id() - get thread id

Threading gotchas

  • A thread is a type-safe interface to a system thread. After construction, a thread starts executing its task as soon as the run-time system can acquire resources for it to run. Think of that as “immediately.”
  • Do not destroy a running thread; Use join() to wait for a thread to complete
  • don’t pass pointers to your local data to other threads
  • beware of by-reference context bindings in lambdas
  • a thread can be moved but not copied
  • thread constructors are variadic templates - to pass a reference to a thread constructor, must use a reference wrapper

Locking

  • mutex - lock(), unlock(), try_lock()
  • recursive_mutex - can be repeatedly acquired without blocking
  • timed_mutex - try_lock_until(tp), try_lock_for(d)
  • recursive_timed_mutex
  • lock_guard<T> - guard for a mutex - simplest
  • unique_lock<T> - lock for a mutex - supports timed ops
  • A mutex cannot be copied or moved
  • lock_guard<mutex> g {mtx}; - destructor does the necessary unlock() on its argument.
  • owns_lock() - check whether an acquisition succeeded

Ensure that a function is executed only once across multiple threads

  • once_flag
  • call_once()

Signaling between threads

  • condition_variable - ::wait(), ::wait_until(), ::wait_for() , ::notify_one(), notify_all() - like a WaitHandle on a unique_lock<mutex>
  • condition_variable_any - like a condition_variable but can use any lockable object

The the promise-future paradigm for 'async callbacks'

  • A future is a handle to a shared state. It is where a task can retrieve a result deposited by a promise
  • The status of a future can be observed by calling wait_for() and wait_until(). the result can be retrieved via ::get()
        future<double> fd = async(square,2);
        double d = fd.get();
  • shared_future<T> - can read result multiple times
auto handle = async(task,args);
res = handle.get()                 // get the result
  • future_error exception with the error condition broken_promise
  • promise - ::set_value, ::set_exception
  • A packaged_task can be moved but not copied. ::get_future()
packaged_task<int(int)> pt1 {DoSomething};
pt1(1);
  • Don’t set_value() or set_exception() to a promise twice. Don’t get() twice from a future;
  • Use async() to launch simple tasks

C++ is not C

IO and strings The C way:

  • <stdio> - fopen(), fclose(), mode flag
  • printf(), fprintf(), sprintf()
  • stdin, stdout, stderr
  • scanf()
  • getc(), putc(), getchar(), putchar()
  • <string.h> - strlen(), strcpy(), strcat(), strcmp(), strstr()
  • atoi

IO and strings The C++ way: streams

  • <istream>, <ostream>
  • iostream
  • Forward declarations for stream types and stream objects are provided in <iosfwd>
  • cin, cout, cerr, clog
  • <fstream> - ifstream, ofstream, fstream
  • <sstream> - istringstream, ostringstream, stringstream
  • ios::ate - write at end
  • use str() to read a result
  • state functions: good(), eof(), fail(), bad()
  • getline(), get(c)
  • put(), write(), flush()
  • noskipws
  • cin >> c1 >> x >> c2 >> y >> c3;
  • peek, seekg
ostream& operator<<(ostream& os, const Named_val& nv) {
  return os << '{' << nv.name << ':' << nv.value << '}';
}
  • basic_ios class manages the state of a stream: buffers, formatting, locales, Error handling
  • streambuf
  • istreambuf_iterator and ostreambuf_iterator
  • An ostreambuf_iterator writes a stream of characters to an ostream_buffer
  • sto* (String to) functions

Time The C way:

  • <ctime> - clock_t, time_t, tm

Time The C++ way: duration

  • std::chrono namespace FROM <chrono>
  • high_resolution_clock, duration_cast<T>
  • duration, time_point
  • call now() for one of 3 clocks: system_clock, steady_clock, high_resolution_clock
  • duration_cast<milliseconds>(d).count()
  • ratio<1>
  • duration<si45, micro> -SI units from <ratio> constructed from ratio<int,int>

Some low level C features may still be handy in a C++ program

  • memory.h: memcpy(), memove(), memcmp(), memset(), calloc(), malloc(), realloc(), free()
  • cmp() , qsort() , bsort()
  • safe fast low level C style copy: if (is_pod<T>::value) memcpy( ...
  • initialize a char array:
char* p = L“…”;
"" == const char* p = '\0';
  • prefixes: L for wide chars, R for raw strings

Some best practice Takeaways:

  • using namespace std; - place in cpp files after includes to make your code more succinct
  • prefer {}-style initializers and using for type aliases
  • Use constructor/destructor pairs to simplify resource management (RAII).
  • Use containers and algorithms rather than built-in arrays and ad hoc code
  • Prefer standard-library facilities to locally developed code
  • Use exceptions, rather than error codes, to report errors that cannot be handled locally
  • Use move semantics to avoid copying large objects
  • Avoid “naked” new and delete. Use unique_ptr / shared_ptr
  • Use templates to maintain static type safety (eliminate casts) and avoid unnecessary use of class hierarchies
  • Header files - semi-independent code fragments minimize compilation times
  • Pointers - a fixed-size handle referring to a variable amount of data “elsewhere”
  • use namespaces for scope: namespace {}
  • establish class invariants in constructors (throw exceptions -> fail fast)
  • static_assert - only works on constant expressions (useful in generics)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.