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
,constexpr
functions rather than#DEFINE
, macros - Avoid
void*
,union
, and raw casts (usestatic_cast
instead) - use
std:string
instead 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”
new
anddelete
; instead, use containers (e.g.,vector
,string
, andmap
) and handle classes (e.g.,lock
andunique_ptr
). - minimal run-time reflection:
dynamic_cast
andtypeid
- Namespaces are non-modular - headers can introduce name clashes - avoid
using
directives in header files, because it increases the chances of name clashes
- 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 ofNULL
) - The
range
-for
statement - Override controls:
final
andoverride
- 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()
regexp
unique_ptr
,shared_ptr
tuple
bind()
,function
decltype(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<<pf
meanspf(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
constexpr
toconst
- 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
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)
- 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 != nullptr
auto
- 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 var
move
uses “ref ref”:move(x)
meansstatic_cast<X&&>(x)
whereX&
is the type ofx
.
struct
,union
,enum
,enum class
enum class
vsenum
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
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);
- 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
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
nothrow
guarantee for some operations
errno
vs<stdexcept>
throw ex
throw;
- rethrowcatch (std::exception& err) {
catch (...)
catch (...) {
cerr << "x"
}
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
exception::what()
current_exception()
rethrow_exception()
make_exception_ptr()
exception_ptr
nested_exception
terminate()
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
<
,=
, 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_assert
vs runtime macro<cassert>
assert
packaged_task
does 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
extern
for 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,const
s,constexpr
s, andinline
s 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.
=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.
- 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
- 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 aComplex
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) ;
- 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
should only appear in .h files override
andfinal
are compiler hintsoverride
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 {
- deriving from a base class can be declared
private
,protected
, orpublic
- 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 aD*
to aB*
- 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 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
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.
- 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_if
andconditional
,declval<X>
const_cast
for getting write access to something declaredconst
static_cast
for reversing a well-defined implicit conversionreinterpret_cast
for changing the meaning of bit patternsdynamic_cast
- is run-time checked - it supports polymorphic class hierarchies
- dynamic_cast used an upcast - returns
nullptr
otherwise.
if (auto px = dynamic_cast<MyClass*>(py)){}
- dont use a ref:
dynamic_cast<MyClass&>
- could throw abad_cast
dynamic_cast
cannot cast from avoid*
. For that, astatic_cast
is 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:
#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
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<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_if
to 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
Estd
namespace – template constraintsOrdered<X>
,Equality_comparable<T>
,Destructible<T>
,Copy_assignable<T>
, etc- implement a concept as a
constexpr
templated 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>::value
iterator_traits
<type_traits>
Enable_if<Is_class<T>(),T>* operator–>();
- select a member (for classes only)std::is_integral
andstd::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_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 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_back
does a copy viaback_inserter
forward_list
- SLLmultiset
/multimap
- values can occur multiple timesunordered_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 algovalarray
- matrix slicingunordered_map / set
;multimap / set
bitset
- 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
_if
suffix 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_copy
remove()
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_difference
lexicographical_compare()
- order words in dictionariesmin
&max
- Use
for_each()
andtransform()
only when there is no more-specific algorithm for a task
[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
}
- 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 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 aniterator
from areverse_iterator
T[N]
vsarray<T,N>
(raw array vs array type) - Usearray
where you need a sequence with aconstexpr
size. Preferarray
over built-in arraysbitset<N>
vsvector<bool>
- Usebitset
if 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_1
fromstd::placeholders
ref()
- 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)
function
is specified with a specific return type and a specific argument type. Usefunction
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
- 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 type
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
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 reference
shared_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_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 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_list
elements 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_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
toshared_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 ashared_ptr
using the member functionlock()
:
if (auto q = p.lock()) {
} else {
p.reset();
}
- specializations of the
numeric_limits
template presented in<limits>
numeric_limits<unsigned char>::max()
<climits>
-DBL_MAX
andFLT_MAX
C 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)gslice
is 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>::get
packaged_task<Task_Type> ::get_future()
async::get
thread_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:
load
andstore
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_flag
are calledset
andclear
. 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_mutex
lock_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_flag
call_once()
condition_variable
-::wait()
,::wait_until()
,::wait_for()
,::notify_one()
,notify_all()
- like aWaitHandle
on aunique_lock<mutex>
condition_variable_any
- like acondition_variable
but can use any lockable object
- 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()
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 result
future_error
exception with the error conditionbroken_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()
orset_exception()
to apromise
twice. Don’tget()
twice from afuture
; - Use
async()
to launch simple tasks
<stdio>
-fopen()
,fclose()
,mode
flagprintf()
,fprintf()
,sprintf()
stdin
,stdout
,stderr
scanf()
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
,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 handlingstreambuf
istreambuf_iterator
andostreambuf_iterator
- An
ostreambuf_iterator
writes a stream of characters to anostream_buffer
sto*
(String to) functions
<ctime>
-clock_t
,time_t
,tm
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 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:
L
for wide chars,R
for 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”
new
anddelete
. 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)