This post is based upon the standard - not supported with VC compiler ! Try these techniques using GCC / LLVM compilers and QtCreator / CLion IDEs
=rather thanstrcpy()for copying ,==rather thanstrcmp()for comparing- use
const,constexprfunctions rather than#DEFINE, macros - Avoid
void*,union, and raw casts (usestatic_castinstead) - use
std:stringinstead ofchar* - avoid pointer arithmetic
- To obey C linkage conventions, a C++ function must be declared to have C linkage
- 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”
newanddelete; instead, use containers (e.g.,vector,string, andmap) and handle classes (e.g.,lockandunique_ptr). - minimal run-time reflection:
dynamic_castandtypeid - Namespaces are non-modular - headers can introduce name clashes - avoid
usingdirectives in header files, because it increases the chances of name clashes
- Constructor Controls
=deleteand=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 ofNULL) - The
range-forstatement - Override controls:
finalandoverride - 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, andlock - asynchronous computation:
future,promise, andasync() regexpunique_ptr,shared_ptrtuplebind(),functiondecltype(expr)- reuse a type
- overloading IO stream ops:
ostream& operator<<(ostream& os, const Entry& e)
istream& operator>>(istream& is, Entry& e)cout <<,cin >>- stdio streamsgetline()- 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<<pfmeanspf(cout). Such a function is called a manipulator <sstream> istringstream- A stream that reads from a stringc_str()returns a C-style pointer to a zero-terminated array of characters
sizeof(T)
extent <decltype( T )> ::value- size of an array must be a constant expression
- use initializer lists
{}instead of=,()- prevents narrowing conversions - with
auto, need to use= - prefer
constexprtoconst- compile time evaluation
v.begin()andv.end()orbegin(v)andend(v)for (const auto& x : v)- for each x in vfor (int& x : v)- to modify an element in a range-for loop, the element variable should be a reference
- 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]; }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);
}- pass & return references
&from functions. - never return a pointer
*. can return a smart pointer. - Return containers by value (relying on
movefor 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)
- To support the range-for loop for a container handle, must define suitable
begin()andend()functions:
template<typename T>
T* begin(Handle<T>& x)
{}- 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)- 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
- error: narrowing
bool b2 {7}; {}indicates default value (nullptr for pointers)if (p) {- equivalent top != nullptrauto- use=, because{}is deduced tostd::initializer_list<T>- The only really good case for an uninitialized variable is a large input buffer.
- only stack variables are default initialized !
- 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);- 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 aT*by val - preferable to pass a reference to some container
- 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 varmoveuses “ref ref”:move(x)meansstatic_cast<X&&>(x)whereX&is the type ofx.
struct,union,enum,enum classenum classvsenum
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.
[[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
inlinekeyword - declare a static function - keyword
staticin 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);- unique function signature check ignores
constin params - Function argument names are not part of the function type
- an argument is unused in a function definition by not naming it
if (something_wrong) exit(1);terminate()- does not invoke destructors. callsabort()std::set_terminate()quick_exit(),at_quick_exit()
- 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
nothrowguarantee for some operations
errnovs<stdexcept>throw exthrow;- rethrowcatch (std::exception& err) {catch (...)
catch (...) {
cerr << "x"
}exception:logic_error,runtime_error,bad_exception,bad_alloc,bad_cast,bad_typeidlogic_error:length_error,domain_error,invalid_argument,out_of_range,future_errorruntime_error:overflow_error,range_error,underflow_error,system_error,regex_error,ios_base::failure
exception::what()current_exception()rethrow_exception()make_exception_ptr()exception_ptrnested_exceptionterminate()
catch exception&- destructors do not throw
- can throw
runtime_errorin 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
<,=, andsort()) 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
- compile-time
static_assertvs runtime macro<cassert>assert
packaged_taskdoes the following:
catch(...) { myPromise.set_exception(current_exception()); }- 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 <iostream>- from standard include directory#include "myheader.h"- from current directory
- external linkage - when definition is not in same TU as declaration, use
externfor external linkage
#ifdef __cplusplus
extern "C" {} // a linkage block
#endif- using, constexpr, static & const not accessible from other TUs - hence
extern const
#define PRINT(a,b) cout<<(a)<<(b)- concatenate: Writing
#x " = "rather than#x << " = "is obscure “clever code” - predefined macros:
__FUNC__,__FILE__,__LINE__
- 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, andinlines 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
- 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();- 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.
=defaultand=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.
- 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
protectedbase
- constructor initialization lists
- const functions and mutable fields
- friend class / functions
- defining an abstract base class
- abstract base class definition (
.cpp):virtual ~Base() = 0;
- 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
- default initialization
MyClass o1 {}; - memberwise initialization
MyClass o2 {"aaa", 77 }; - copy initialization
MyClass o3 { o2 };
- stream out operator:
ostream& operator<<(ostream&, const string&);- calling
std::cout << s;is the same asoperator<<(std::cout, s); - overload the
+and+=operators for aComplexnumber 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) ;- 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,finalshould only appear in .h files overrideandfinalare compiler hintsoverridespecifier comes last in a declaration.virtualfunctions - 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 {- deriving from a base class can be declared
private,protected, orpublic - If B is a
privatebase, its public and protected members can be used only by member functions and friends of D. Only friends and members of D can convert aD*to aB* - If B is a
protectedbase, 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
publicbase, 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 aD*to aB*.
- 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
- Prefer
publicmembers for interfaces; - Use
protectedmembers 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.
- 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
<typeinfo> type_info typeid(x)typ_info.name()size_t typ_info.hash_code()
<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_ifandconditional,declval<X>
const_castfor getting write access to something declaredconststatic_castfor reversing a well-defined implicit conversionreinterpret_castfor changing the meaning of bit patternsdynamic_cast- is run-time checked - it supports polymorphic class hierarchies
- dynamic_cast used an upcast - returns
nullptrotherwise.
if (auto px = dynamic_cast<MyClass*>(py)){}- dont use a ref:
dynamic_cast<MyClass&>- could throw abad_cast dynamic_castcannot cast from avoid*. For that, astatic_castis needed- crosscasting, dynamic dispatch. better to use visitor pattern
class Manager : public Employee {}
void g(Manager mm, Employee ee) {
Employee* pe = &mm; // OK: every Manager is an Employee
Manager* pm = ⅇ // 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
}- 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
}- explicit:
new(&s) string{"xxx"};- placement new: explicitly construct strings.~string();- explicitly destroy string- for
enum class, defineoperator|(),operator&() allocator<T>
- 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
- 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:
#includethe.cppdefinition 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
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() {} // ctortemplate<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>&);
}- 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>)- A template substitution failure is not an error. It simply causes the template to be ignored;
- use
enable_ifto conditionally remove functions from overload resolution
using IntVector = vector<int>;- 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
Estdnamespace – template constraintsOrdered<X>,Equality_comparable<T>,Destructible<T>,Copy_assignable<T>, etc- implement a concept as a
constexprtemplated function withstatic_assert - parameterized --> constraint checks
- 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- 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 can be deduced from the function argument list, we need not specify it explicitly:
template<>
bool less(const char* a, const char* b)- 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 )
- 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 itScoped<T>,On_heap<T>template<typename T>using Holder = typename Obj_holder<T>::type;is_pod<T>::valueiterator_traits<type_traits>Enable_if<Is_class<T>(),T>* operator–>();- select a member (for classes only)std::is_integralandstd::is_floating_point
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);<utility>operators & pairs<tuple><type_traits><typeindex>use atype_infoas 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>-exceptionclass<stdexcept>- standard exceptions<cassert>-assertmacro<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>-iostreambases<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>-printffamily of IO<cwchar>-printffamily 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 supportsizeof(),size_t,ptrdiff_t,NULL<cstdarg>- variable length function args<csetjmp>- C-style stack unwinding:setjmp,longjmp<cstdlib>- program termination , C-style math functions egabs(),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>
- 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_backdoes a copy viaback_inserterforward_list- SLLmultiset/multimap- values can occur multiple timesunordered_XXstream_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 algovalarray- matrix slicingunordered_map / set;multimap / setbitset- array of boolpair<T,U>,tuple<W,X,Y,Z>
less<T>copy(),find(),sort(),merge(),cmp(),equiv(),swap(),binary_search(),splice()size(),capacity()at()- range checksemplace- nice and terse move push_backhash<T>- functor- efficiently moving items from one container to another
copy(c1,make_move_iterator(back_inserter(c2))); // move strings from c1 into c2- 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
_ifsuffix is often used to indicate that an algorithm takes a predicate as an additional argument.
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 subsequencetransform(b,e,out,f)copy(b,e,out),move(b,e,out)copy_if(b,e,out,f)unique,unique_copyremove()andreplace()reverse()rotate(),random_shuffle(), andpartition()- separates into 2 partsnext_permutation(),prev_permutation(),is_permutation()- generate permutations of a sequencefill(),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-sortedmerge()- combine 2 pre-sorted sequencesset_union,set_intersection,set_differencelexicographical_compare()- order words in dictionariesmin&max- Use
for_each()andtransform()only when there is no more-specific algorithm for a task
[b:e)endpoints 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
}- input (++ , read istream), output (++, write ostream), forward (++ rw), bidirectional(++, --), random access
iterator_traits- select among algorithms based on the type of an iterator++pis likely to be more efficient thanp++.- 3 insert iterators:
insert_iterator- inserts before the element pointed to usinginsert().front_insert_iterator- inserts before the first element of a sequence usingpush_front().back_insert_iterator- inserts after the last element of the sequence usingpush_back().- Use
base()to extract aniteratorfrom areverse_iterator
T[N]vsarray<T,N>(raw array vs array type) - Usearraywhere you need a sequence with aconstexprsize. Preferarrayover built-in arraysbitset<N>vsvector<bool>- Usebitsetif you need N bits and N is not necessarily the number of bits in a built-in integer type. Avoidvector<bool>pair<T,U>vstuple<T...>- usemake_pair()/make_tuple()for type deduction.tie()can be used to extract elements from a tuple as out paramsbasic_string<C>,valarray<T>
- mem management problems: leaks, premature deletion, double deletion
int* p2 = p1;- potential trouble- handles, RAII, move semantics eliminate problems
<functional>- function adaptors - take a function as argument and return a functor that can be used to invoke itbind(f,args),mem_fn(f),not(f)- currying, partial evaluation. more easily expressed using lambdas. Uses_1fromstd::placeholdersref()- likebind(), 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 thep–>f(a)calling convention intof(p,a)functionis specified with a specific return type and a specific argument type. Usefunctionwhen 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- lambda default is all by reference:
[&] [=]by value (copy). recommended for passing a lambda to another threadmutable- capture values can changefor_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 typestd::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
unique_ptr- note: there is nomake_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 referenceshared_ptr– create withmake_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_ptrare copied ,unique_ptrare 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 thanvector<Item*>orvector<Item>, because all items implicitly destroyed
- 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_listelements are immutable, cannot apply a move constructor - useuninitialized_copy
- 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- 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 hashingtype_index(created from atype_info)
p=a.allocate(n);- acquire space for n objects of type Ta.deallocate(p,n);- release space for n objects of type T pointed to by p
unique_ptrcannot 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_ptrtoshared_ptr. - Prefer ordinary scoped objects to objects on the heap owned by a
unique_ptr - Minimize the use of
weak_ptr - a
weak_ptrcan be converted to ashared_ptrusing the member functionlock():
if (auto q = p.lock()) {
} else {
p.reset();
}- specializations of the
numeric_limitstemplate presented in<limits> numeric_limits<unsigned char>::max()<climits>-DBL_MAXandFLT_MAXC Macros
valarray- slices and strides for matricesslice_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)gsliceis a “generalized slice” that contains (almost) the information from n slicesaccumulate()adds elements of a sequence using their + operator:inner_product(),partial_sum()andadjacent_difference()iota(b,e,n)assigns n+i to the ith element of[b:e).
<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();atomic,thread,condition_variable,mutex,future+promise,packaged_task, andasync()
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 locking:
defer_lock&explicit lock() condition_variable-::wait(),::notify_one()promise<T>::set_value(),future<T>::getpackaged_task<Task_Type> ::get_future()async::getthread_local
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 ...
}- simplest memory order is sequentially consistent
- Atomics - Lock-free programming:
loadandstore
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 callskill_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_flagare calledsetandclear. atomic_thread_fence,atomic_signal_fence- barriersvolatile
- 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 storagethread::hardware_concurrency()- reports the number of tasks that can simultaneously proceed with hardware supportthread::get_id()- get thread id
- 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
mutex-lock(),unlock(),try_lock()recursive_mutex- can be repeatedly acquired without blockingtimed_mutex-try_lock_until(tp),try_lock_for(d)recursive_timed_mutexlock_guard<T>- guard for a mutex - simplestunique_lock<T>- lock for a mutex - supports timed ops- A mutex cannot be copied or moved
lock_guard<mutex> g {mtx};- destructor does the necessaryunlock()on its argument.owns_lock()- check whether an acquisition succeeded
once_flagcall_once()
condition_variable-::wait(),::wait_until(),::wait_for(),::notify_one(),notify_all()- like aWaitHandleon aunique_lock<mutex>condition_variable_any- like acondition_variablebut can use any lockable object
- A
futureis 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()andwait_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 resultfuture_errorexception with the error conditionbroken_promisepromise-::set_value,::set_exception- A
packaged_taskcan be moved but not copied.::get_future()
packaged_task<int(int)> pt1 {DoSomething};
pt1(1);- Don’t
set_value()orset_exception()to apromisetwice. Don’tget()twice from afuture; - Use
async()to launch simple tasks
<stdio>-fopen(),fclose(),modeflagprintf(),fprintf(),sprintf()stdin,stdout,stderrscanf()getc(),putc(),getchar(),putchar()<string.h>-strlen(),strcpy(),strcat(),strcmp(),strstr()atoi
<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,stringstreamios::ate- write at end- use
str()to read a result - state functions:
good(),eof(),fail(),bad() getline(),get(c)put(),write(),flush()noskipwscin >> c1 >> x >> c2 >> y >> c3;peek,seekg
ostream& operator<<(ostream& os, const Named_val& nv) {
return os << '{' << nv.name << ':' << nv.value << '}';
}basic_iosclass manages the state of a stream: buffers, formatting, locales, Error handlingstreambufistreambuf_iteratorandostreambuf_iterator- An
ostreambuf_iteratorwrites a stream of characters to anostream_buffer sto*(String to) functions
<ctime>-clock_t,time_t,tm
std::chrononamespace 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 fromratio<int,int>
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:
Lfor wide chars,Rfor raw strings
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”
newanddelete. Useunique_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)