Preprocessor directives

Preprocessor directives are lines included in the code of programs preceded by a hash sign (#). These lines are not program statements but directives for the preprocessor. The preprocessor examines the code before actual compilation of code begins and resolves all these directives before any code is actually generated by regular statements.

These preprocessor directives extend only across a single line of code. As soon as a newline character is found, the preprocessor directive is ends. No semicolon (;) is expected at the end of a preprocessor directive. The only way a preprocessor directive can extend through more than one line is by preceding the newline character at the end of the line by a backslash (\).

macro definitions (#define, #undef)

#define identifier replacement
#define TABLE_SIZE 100
int table1[TABLE_SIZE];
int table2[TABLE_SIZE];
 // function macro
#include <iostream>
using namespace std;

#define getmax(a,b) ((a)>(b)?(a):(b))

int main()
{
  int x=5, y;
  y= getmax(x,2);
  cout << y << endl;
  cout << getmax(7,x) << endl;
  return 0;
}
#define TABLE_SIZE 100
int table1[TABLE_SIZE];
#undef TABLE_SIZE
#define TABLE_SIZE 200
int table2[TABLE_SIZE];

This would generate the same code as:

int table1[100];
int table2[200];

Function macro definitions accept two special operators (# and ##) in the replacement sequence:
The operator #, followed by a parameter name, is replaced by a string literal that contains the argument passed (as if enclosed between double quotes):

#define str(x) #x
cout << str(test);

The operator ## concatenates two arguments leaving no blank spaces between them:

#define glue(a,b) a ## b
glue(c,out) << "test";
#define AA(a,b)#a###b

int main(int argc,char *argv[])
{
    qDebug()<<AA(v1,_m);//v1_m
}

Conditional inclusions (#ifdef, #ifndef, #if, #endif, #else and #elif)

#ifdef TABLE_SIZE
int table[TABLE_SIZE];
#endif  
#ifndef TABLE_SIZE
#define TABLE_SIZE 100
#endif
int table[TABLE_SIZE];
#if TABLE_SIZE>200
#undef TABLE_SIZE
#define TABLE_SIZE 200
 
#elif TABLE_SIZE<50
#undef TABLE_SIZE
#define TABLE_SIZE 50
 
#else
#undef TABLE_SIZE
#define TABLE_SIZE 100
#endif
 
int table[TABLE_SIZE];
#if defined ARRAY_SIZE
#define TABLE_SIZE ARRAY_SIZE
#elif !defined BUFFER_SIZE
#define TABLE_SIZE 128
#else
#define TABLE_SIZE BUFFER_SIZE
#endif

Rvalue References

Understand std::move

Because std::move does nothing but cast its argument to an rvalue, there have been
suggestions that a better name for it might have been something like rvalue_cast.

//c++11
template<typename T> // in namespace std
typename remove_reference<T>::type&&
move(T&& param)
{
 using ReturnType = // alias declaration;
 typename remove_reference<T>::type&&;
 return static_cast<ReturnType>(param);
}

// C++14; still in
template<typename T>
decltype(auto) move(T&& param) // namespace std
{
 using ReturnType = remove_reference_t<T>&&;
 return static_cast<ReturnType>(param);
}

Distinguish universal references from rvalue
references.

• If a function template parameter has type T&& for a deduced type T, or if an object is declared using auto&&, the parameter or object is a universal reference.
• If the form of the type declaration isn’t precisely type&&, or if type deduction does not occur, type&& denotes an rvalue reference.
• Universal references correspond to rvalue references if they’re initialized with rvalues. They correspond to lvalue references if they’re initialized with lvalues.

void f(Widget&& param); // rvalue reference
Widget&& var1 = Widget(); // rvalue reference
auto&& var2 = var1; // is a universal reference
template<typename T>
void f(std::vector<T>&& param); // rvalue reference
template<typename T>
void f(T&& param); // is a universal reference
template<typename T>
void f(std::vector<T>&& param); // param is an rvalue reference
std::vector<int> v;
f(v); // error! can't bind lvalue to
 // rvalue reference
auto timeFuncInvocation =
 [](auto&& func, auto&&... params) // C++14
 {
 start timer;
 std::forward<decltype(func)>(func)( // invoke func
 std::forward<decltype(params)>(params)... // on params
 );
 stop timer and record elapsed time;
 };

Use std::move on rvalue references,
std::forward on universal references.

• Apply std::move to rvalue references and std::forward to universal refer‐
ences the last time each is used.
• Do the same thing for rvalue references and universal references being
returned from functions that return by value.
• Never apply std::move or std::forward to local objects if they would other‐
wise be eligible for the return value optimization.

class Widget {
public:
 Widget(Widget&& rhs) // rhs is rvalue reference
 : name(std::move(rhs.name)),
 p(std::move(rhs.p))
 { … }
 …
private:
 std::string name;
 std::shared_ptr<SomeDataStructure> p;
};
class Widget {
public:
 template<typename T>
 void setName(T&& newName) // newName is
 { name = std::forward<T>(newName); } // universal reference
 …
};

using std::move with universal references,that can have the
effect of unexpectedly modifying lvalues

Matrix // by-value return
operator+(Matrix&& lhs, const Matrix& rhs)
{
 lhs += rhs;
 return std::move(lhs); // move lhs into
} 

Matrix // as above
operator+(Matrix&& lhs, const Matrix& rhs)
{
 lhs += rhs;
 return lhs; // copy lhs into
} 

template<typename T>
Fraction // by-value return
reduceAndCopy(T&& frac) // universal reference param
{
 frac.reduce();
 return std::forward<T>(frac); // move rvalue into return
} 

don’t move local variable into return value

Widget makeWidget() // Moving version of makeWidget
{
 Widget w;
 …
 return std::move(w); // move w into return value
} 

Avoid overloading on universal references

std::multiset<std::string> names; // global data structure
void logAndAdd(const std::string& name)
{
 auto now = // get current time
 std::chrono::system_clock::now();
 log(now, "logAndAdd"); // make log entry
 names.emplace(name); // add name to global data
} 
std::string petName("Darla");
logAndAdd(petName); // pass lvalue std::string
logAndAdd(std::string("Persephone")); // pass rvalue std::string
logAndAdd("Patty Dog"); // pass string literal

in the previous example in second and third call name itself is an lvalue, so it’s copied into names.

template<typename T>
void logAndAdd(T&& name)
{
 auto now = std::chrono::system_clock::now();
 log(now, "logAndAdd");
 names.emplace(std::forward<T>(name));
}
std::string petName("Darla"); // as before
logAndAdd(petName); // as before, copy lvalue into multiset
logAndAdd(std::string("Persephone")); // move rvalue instead of copying it
logAndAdd("Patty Dog"); // create std::string in multiset instead of copying a temporary std::string

Constraining templates that take universal references

Alternatives to the combination of universal references and overloading
include the use of distinct function names, passing parameters by lvaluereference-to-const, passing parameters by value, and using tag dispatch.
• Constraining templates via std::enable_if permits the use of universal references and overloading together, but it controls the conditions under which compilers may use the universal reference overloads.
• Universal reference parameters often have efficiency advantages, but they typically have usability disadvantages.

class Person {
public:
 template<
 typename T,
 typename = typename std::enable_if<!std::is_base_of<Person,typename std::decay<T>::type>::value>::type>
 explicit Person(T&& n);
 …
};

//c++14
class Person {
public:
 template<
 typename T,
 typename = std::enable_if_t<!std::is_base_of<Person,std::decay_t<T>>::value>>
 explicit Person(T&& n);
 …
};

#include <type_traits>

template<typename T>
class YourClass {

    YourClass() {
        // Compile-time check
        static_assert(std::is_base_of<BaseClass, T>::value, "type parameter of this class must derive from BaseClass");

        // ...
    }
}
class Person {
public:
    template<typename T,typename = std::enable_if_t<std::is_base_of_v<Person,std::decay_t<T>>>>
    explicit Person(T&& n){
    }
    Person()= default;
};
int main(int argc,char* argv[]){
    Person pp;
    Person p(pp);
    return 0;
}

Moving to Modern C++

Distinguish between () and {} when creating objects

class Widget {
public:
 Widget(int i, bool b); // ctors not declaring
 Widget(int i, double d); // std::initializer_list params
 …
};
Widget w1(10, true); // calls first ctor
Widget w2{10, true}; // also calls first ctor
Widget w3(10, 5.0); // calls second ctor
Widget w4{10, 5.0}; // also calls second ctor
class Widget {
public:
 Widget(int i, bool b); // as before
 Widget(int i, double d); // as before
Widget(std::initializer_list<long double> il); // added
 …
};
Widget w1(10, true); // uses parens and, as before,
 // calls first ctor
Widget w2{10, true}; // uses braces, but now calls
 // std::initializer_list ctor
// (10 and true convert to long double)
Widget w3(10, 5.0); // uses parens and, as before,
 // calls second ctor
Widget w4{10, 5.0}; // uses braces, but now calls
 // std::initializer_list ctor
// (10 and 5.0 convert to long double)
class Widget {
public:
 Widget(int i, bool b); // as before
 Widget(int i, double d); // as before
 Widget(std::initializer_list<long double> il); // as before
 operator float() const; // convert
 … // to float
};
Widget w5(w4); // uses parens, calls copy ctor
Widget w6{w4}; // uses braces, calls std::initializer_list ctor (w4 converts to float, and float converts to long double)
Widget w7(std::move(w4)); // uses parens, calls move ctor
Widget w8{std::move(w4)}; // uses braces, calls std::initializer_list ctor (for same reason as w6)
class Widget {
public:
 Widget(int i, bool b); // as before
 Widget(int i, double d); // as before
 // std::initializer_list element type is now std::string
 Widget(std::initializer_list<std::string> il);
 … // no implicit
}; // conversion funcs
Widget w1(10, true); // uses parens, still calls first ctor
Widget w2{10, true}; // uses braces, now calls first ctor
Widget w3(10, 5.0); // uses parens, still calls second ctor
Widget w4{10, 5.0}; // uses braces, now calls second ctor
class Widget {
public:
 Widget(); // default ctor
 Widget(std::initializer_list<int> il); // std::initializer
 // _list ctor
 … // no implicit
}; // conversion funcs
Widget w1; // calls default ctor
Widget w2{}; // also calls default ctor
Widget w3(); // most vexing parse! declares a function!
Widget w4({}); // calls std::initializer_list ctor with empty list
Widget w5{{}}; // ditto
std::vector<int> v1(10, 20); // use non-std::initializer_list
 // ctor: create 10-element
// std::vector, all elements have
// value of 20
std::vector<int> v2{10, 20}; // use std::initializer_list ctor:
 // create 2-element std::vector,
// element values are 10 and 20
template<typename T, // type of object to create
 typename... Ts> // types of arguments to use
void doSomeWork(Ts&&... params)
{
 create local T object from params...
 …
}
T localObject(std::forward<Ts>(params)...); // using parens
T localObject{std::forward<Ts>(params)...}; // using braces

Prefer nullptr to 0 and NULL

void f(int); // three overloads of f
void f(bool);
void f(void*);
f(0); // calls f(int), not f(void*)
f(NULL); // might not compile, but typically calls
 // f(int). Never calls f(void*)
f(nullptr); // calls f(void*) overload

Prefer alias declarations to typedefs

Avoiding such medical tragedies is easy. Introduce a typedef:

typedef std::unique_ptr> UPtrMapSS;

But typedefs are soooo C++98. They work in C++11, sure, but C++11 also offers alias declarations:

using UPtrMapSS = std::unique_ptr>;
// FP is a synonym for a pointer to a function taking an int and
// a const std::string& and returning nothing
typedef void (*FP)(int, const std::string&); // typedef
// same meaning as above
using FP = void (*)(int, const std::string&); // alias
 // declaration
template<typename T> // MyAllocList<T>
using MyAllocList = std::list<T, MyAlloc<T>>; // is synonym for
 // std::list<T,
// MyAlloc<T>>
MyAllocList<Widget> lw; // client code

template<typename T> // MyAllocList<T>::type
struct MyAllocList { // is synonym for
 typedef std::list<T, MyAlloc<T>> type; // std::list<T,
}; // MyAlloc<T>>
MyAllocList<Widget>::type lw; // client code

• typedefs don’t support templatization, but alias declarations do.
• Alias templates avoid the “::type” suffix and, in templates, the “typename”
prefix often required to refer to typedefs

template <class T>
using remove_const_t = typename remove_const<T>::type;
template <class T>
using remove_reference_t = typename remove_reference<T>::type;
template <class T>
using add_lvalue_reference_t = typename add_lvalue_reference<T>::type;

Prefer scoped enums to unscoped enums

enum Color { black, white, red }; // black, white, red are in same scope as Color
auto white = false; // error! white already declared in this scope

enum class Color { black, white, red }; // black, white, red are scoped to Color
auto white = false; // fine, no other
Color c = white; // error! no enumerator named "white" is in this scope
Color c = Color::white; // fine
auto c = Color::white; // also fine (and in accord with Item 5's advice)
enum Color { black, white, red }; // unscoped enum
std::vector<std::size_t> // func. returning
 primeFactors(std::size_t x); // prime factors of x
Color c = red;
…
if (c < 14.5) { // compare Color to double (!)
 auto factors = // compute prime factors
 primeFactors(c); // of a Color (!)
 …
}
enum class Color { black, white, red }; // enum is now scoped
Color c = Color::red; // as before, but
… // with scope qualifier
if (c < 14.5) { // error! can't compare Color and double
auto factors = // error! can't pass Color to
 primeFactors(c); // function expecting std::size_t
 …
}
if (static_cast<double>(c) < 14.5) { // odd code, but
 // it's valid
 auto factors = // suspect, but
 primeFactors(static_cast<std::size_t>(c)); // it compiles
 …
}

Prefer deleted functions to private undefined ones.

template <class charT, class traits = char_traits<charT> >
class basic_ios : public ios_base {
public:
 …
private:
 basic_ios(const basic_ios& ); // not defined
 basic_ios& operator=(const basic_ios&); // not defined
};
//instead prefer to use delete
template <class charT, class traits = char_traits<charT> >
class basic_ios : public ios_base {
public:
 …
 basic_ios(const basic_ios& ) = delete;
 basic_ios& operator=(const basic_ios&) = delete;
 …
};
void fun(int k)
void fun(char)=delete;
void fun(double)=delete;
fun(12);//ok
fun('a');//error
fun(4.5);//error
class Widget {
public:
 …
 template<typename T>
 void processPointer(T* ptr)
 { … }
 …
};
template<> // still
void Widget::processPointer<void>(void*) = delete; // public, but deleted

Deducing Types

Template

template<typename T>
void f(T& param); // param is a reference
//and we have these variable declarations,
int x = 27; // x is an int
const int cx = x; // cx is a const int
const int& rx = x; // rx is a reference to x as a const int
//the deduced types for param and T in various calls are as follows:
f(x); // T is int, param's type is int&
f(cx); // T is const int,
 // param's type is const int&
f(rx); // T is const int,
 // param's type is const int&

universal reference

template<typename T>
void f(T&& param); // param is now a universal reference
int x = 27; // as before
const int cx = x; // as before
const int& rx = x; // as before
f(x); // x is lvalue, so T is int&, param's type is also int&
f(cx); // cx is lvalue, so T is const int&, param's type is also const int&
f(rx); // rx is lvalue, so T is const int&, param's type is also const int&
f(27); // 27 is rvalue, so T is int,param's type is therefore int&&

not pointer or reference

template<typename T>
void f(T param); // param is now passed by value
int x = 27; // as before
const int cx = x; // as before
const int& rx = x; // as before
f(x); // T's and param's types are both int
f(cx); // T's and param's types are again both int
f(rx); // T's and param's types are still both int
template<typename T>
void f(T param); // param is still passed by value
const char* const ptr = // ptr is const pointer to const object "Fun with pointers";
f(ptr); // pass arg of type const char * const

Array Arguments

template<typename T, std::size_t N> // see info
constexpr std::size_t arraySize(T (&)[N]) noexcept // below on
{
    return N; // and
} 
int keyVals[] = { 1, 3, 7, 9, 11, 22, 35 }; // keyVals has 7 elements
int mappedVals[arraySize(keyVals)]; // so does mappedVals

Auto

auto x = 27; // case 3 (x is neither ptr nor reference)
const auto cx = x; // case 3 (cx isn't either)
const auto& rx = x; // case 1 (rx is a non-universal ref.)
auto&& uref1 = x; // x is int and lvalue,  so uref1's type is int&
auto&& uref2 = cx; // cx is const int and lvalue,  so uref2's type is const int&
auto&& uref3 = 27; // 27 is int and rvalue,  so uref3's type is int&&
const char name[] ="R. N. Briggs"; // name's type is const char[13]
auto arr1 = name; // arr1's type is const char*
auto& arr2 = name; // arr2's type is
void someFunc(int, double); // someFunc is a function;  type is void(int, double)
auto func1 = someFunc; // func1's type is void (*)(int, double)
auto& func2 = someFunc; // func2's type is void (&)(int, double)
auto x5 = { 1, 2, 3.0 }; // error! can't deduce T for std::initializer_list<T>

Decltype

const int i = 0; // decltype(i) is const int
bool f(const Widget& w); // decltype(w) is const Widget& decltype(f) is bool(const Widget&)
struct Point {
 int x, y; // decltype(Point::x) is int
}; // decltype(Point::y) is int
Widget w; // decltype(w) is Widget
if (f(w)) … // decltype(f(w)) is bool
template<typename T> // simplified version of std::vector
class vector {
public:
 …
 T& operator[](std::size_t index);
 …
};
vector<int> v; // decltype(v) is vector<int>
…
if (v[0] == 0) … // decltype(v[0]) is int&
template<typename Container, typename Index> // works, but requires refinement
auto authAndAccess(Container& c, Index i) -> decltype(c[i]) 
{
 authenticateUser();
 return c[i];
}
template<typename Container, typename Index> // C++14;
auto authAndAccess(Container& c, Index i) // not quite
{ // correct
 authenticateUser();
 return c[i]; // return type deduced from c[i]
}
std::deque<int> d;
…
authAndAccess(d, 5) = 10; // authenticate user, return d[5],
 // then assign 10 to it;
// this won't compile!

template<typename Container, typename Index> // C++14; works,but still requires refinement
decltype(auto) 
authAndAccess(Container& c, Index i) 
{ 
 authenticateUser();
 return c[i];
}

Widget w;
const Widget& cw = w;
auto myWidget1 = cw; // auto type deduction: myWidget1's type is Widget
decltype(auto) myWidget2 = cw; // decltype type deduction: myWidget2's type 
    int i=12;
    decltype(i) ii=i;//value
    decltype((i)) iii=i;//reference
    decltype(auto) iiii=i;//reference
decltype(auto) f1()
{
 int x = 0;
 …
 return x; // decltype(x) is int, so f1 returns int
}
decltype(auto) f2()
{
 int x = 0;
 …
 return (x); // decltype((x)) is int&, so f2 returns int&
}

why auto

template<typename It> // algorithm to dwim ("do what I mean")
void dwim(It b, It e) // for all elements in range from
{ // b to e
 while (b != e) {
 typename std::iterator_traits<It>::value_type currValue = *b;
 }
}

and you can use auto instead

template<typename It> // as before
void dwim(It b, It e)
{
 while (b != e) {
 auto currValue = *b;
 …
 }
auto derefUPLess = // comparison func.
 [](const std::unique_ptr<Widget>& p1, // for Widgets
 const std::unique_ptr<Widget>& p2) // pointed to by
 { return *p1 < *p2; }; // std::unique_ptrs
//use auto for all 
auto derefLess = // C++14 comparison
 [](const auto& p1, // function for
 const auto& p2) // values pointed
 { return *p1 < *p2; }; // to by anything
 // pointer-like

CONSTEXPR

Declare functions noexcept if they won’t emit exceptions

Values known during compilation are privileged. They may be placed in read-only memory, for example, and, especially for developers of embedded systems, this can be a feature of considerable importance. Of broader applicability is that integral val‐ ues that are constant and known during compilation can be used in contexts where C++ requires an integral constant expression. Such contexts include specification of array sizes, integral template arguments (including lengths of std::array objects), enumerator values, alignment specifiers, and more. If you want to use a variable for these kinds of things, you certainly want to declare it constexpr, because then com‐ pilers will ensure that it has a compile-time value:

int sz; // non-constexpr variable … 
constexpr auto arraySize1 = sz; // error! sz's value not known at compilation 
std::array data1; // error! same problem 
constexpr auto arraySize2 = 10; // fine, 10 is a compile-time constant
std::array<int, arraySize2> data2; // fine, arraySize2 is constexpr

Note that const doesn’t offer the same guarantee as constexpr, because const
objects need not be initialized with values known during compilation:

int sz; // as before
…
const auto arraySize = sz; // fine, arraySize is const copy of sz
std::array<int, arraySize> data; // error! arraySize's value not known at compilation

Simply put, all constexpr objects are const, but not all const objects are constexpr.
If you want compilers to guarantee that a variable has a value that can beused in contexts requiring compile-time constants, the tool to reach for is constexpr, not const.

constexpr functions can be used in contexts that demand compile-time con‐
stants. If the values of the arguments you pass to a constexpr function in such a context are known during compilation, the result will be computed during compilation. If any of the arguments’ values is not known during compilation,your code will be rejected.

When a constexpr function is called with one or more values that are not
known during compilation, it acts like a normal function, computing its result at runtime. This means you don’t need two functions to perform the same operation, one for compile-time constants and one for all other values. The constexpr function does it all.

constexpr // pow's a constexpr func
int pow(int base, int exp) noexcept // that never throws
{
 … // impl is below
}
constexpr auto numConds = 5; // # of conditions
std::array<int, pow(3, numConds)> results; // results has 3^numConds elements
auto base = readFromDB("base"); // get these values
auto exp = readFromDB("exponent"); // at runtime
auto baseToExp = pow(base, exp); // call pow function at runtime
constexpr int pow(int base, int exp) noexcept
{
 return (exp == 0 ? 1 : base * pow(base, exp - 1));
}

constexpr functions are limited to taking and returning literal types, which essentially means types that can have values determined during compilation. In C++11, all built-in types except void qualify, but user-defined types may be literal, too, because constructors and other member functions may be constexpr:

class Point {
public:
 constexpr Point(double xVal = 0, double yVal = 0) noexcept
 : x(xVal), y(yVal)
 {}
 constexpr double xValue() const noexcept { return x; }
 constexpr double yValue() const noexcept { return y; }
 void setX(double newX) noexcept { x = newX; }
 void setY(double newY) noexcept { y = newY; }
private:
 double x, y;
};
constexpr Point p1(9.4, 27.7); // fine, "runs" constexpr ctor during compilation
constexpr
Point midpoint(const Point& p1, const Point& p2) noexcept
{
 return { (p1.xValue() + p2.xValue()) / 2, // call constexpr
 (p1.yValue() + p2.yValue()) / 2 }; // member funcs
}
constexpr auto mid = midpoint(p1, p2); // init constexpr object w/result of constexpr function

In C++11, two restrictions prevent Point’s member functions setX and setY from being declared constexpr. First, they modify the object they operate on, and in C++11, constexpr member functions are implicitly const. Second, they have void return types, and void isn’t a literal type in C++11. Both these restrictions are lifted in C++14, so in C++14, even Point’s setters can be constexpr:

class Point {
public:
 …
 constexpr void setX(double newX) noexcept // C++14
 { x = newX; }
 constexpr void setY(double newY) noexcept // C++14
 { y = newY; }
 …
};
constexpr Point reflection(const Point& p) noexcept
{
 Point result; // create non-const Point
 result.setX(-p.xValue()); // set its x and y values
 result.setY(-p.yValue());
 return result; // return copy of it
}
constexpr Point p1(9.4, 27.7); // as above
constexpr Point p2(28.8, 5.3);
constexpr auto mid = midpoint(p1, p2);
constexpr auto reflectedMid = // reflectedMid's value is
 reflection(mid); // (-19.1 -16.5) and known  during compilation

containers and Iterators in C++

Iterators

class MyContainer{
public:
    const int* array;
    int size;
    class Iterator{
        const int *obj;
    public:
        Iterator(const int* obj):obj(obj){
        }

        bool operator !=(Iterator other){
            cout<<"call != \n";
            if(other.obj==this->obj)
                return false;
            return true;
        }

        Iterator operator++(){
            obj++;
            cout<<"call ++ \n";
            return *this;
        }

        const int& operator*()const {
            cout<<"call * \n";
            return *obj;
        }

    };
    template <int i>
    MyContainer(int const (&obj)[i]):array(obj),size(i){

    }

    Iterator begin(){
        MyContainer::Iterator iterator(this->array);
        cout<<"call begin\n";
        return iterator;
    }

    Iterator end() {
        MyContainer::Iterator iterator(this->array+size);
        cout << "call begin\n";
        return iterator;

    }
};

int main(int argc,char* argv[]){
    MyContainer mc({1,2,3,4,5,6});
    for(const auto& vv:mc){
        cout<<vv<<endl;
    }

    return 0;
}

simple forward iterator and the result is

call begin
call !=
call *
1
call ++
call !=
call *
2
call ++
call !=
call *
3
call ++
call !=
call *
4
call ++
call !=
call *
5
call ++
call !=
call *
6
call ++
call !=

Iterator categoryPropertiesContainer
Forward iterator++It, It++, *Itunordered associative container
 It == It2, It != It2std::forward_list
Bidirectional iterator--It, It--ordered associative container
  std::list
Random access iteratorIt[i]std::array
 It+= n, It-= nstd::vector
 It+n, It-nstd::deque
 n+Itstd::string
 It-It2 
 It < It2, It <= It2, It > It2 
 It >= It2 
Global functionDescription
std::begin(cont)Returns a begin iterator to the container cont.
std::end(cont)Returns an end iterator to the container cont.
std::rbegin(cont)Returns a reverse begin iterator to the container cont.
std::rend(cont)Returns a reverse end iterator to the container cont.
std::cbegin(cont)Returns a constant begin iterator to the container cont.
std::cend(cont)Returns a constant end iterator to the container cont.
std::crbegin(cont)Returns a reverse constant begin iterator to the container cont.
std::crend(cont)Returns a reverse constant end iterator to the container cont.
std::prev(it)Returns an iterator, which points to a position before it
std::next(it)Returns an iterator, which points to a position after it.
std::distance(fir, sec)Returns the number of elements between fir and sec.
std::advance(it, n)Puts the iterator it n positions further.
general functions
// iteratorUtilities.cpp
...
#include <iterator>
...
using std::cout;

std::unordered_map<std::string, int> myMap{{"Rainer", 1966}, {"Beatrix", 1966},
                                           {"Juliette", 1997}, {"Marius", 1999}};

for (auto m: myMap) cout << "{" << m.first << "," << m.second << "} ";
     // {Juliette,1997},{Marius,1999},{Beatrix,1966},{Rainer,1966}

auto mapItBegin= std::begin(myMap);
cout << mapItBegin->first << " " << mapItBegin->second; // Juliette 1997

auto mapIt= std::next(mapItBegin);
cout << mapIt->first << " " << mapIt->second;            // Marius 1999
cout << std::distance(mapItBegin, mapIt);                 // 1

std::array<int, 10> myArr{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
for (auto a: myArr) std::cout << a << " ";               // 0 1 2 3 4 5 6 7 8 9

auto arrItEnd= std::end(myArr);
auto arrIt= std::prev(arrItEnd);
cout << *arrIt << std::endl;                             // 9

std::advance(arrIt, -5);
cout << *arrIt;                                          // 4

Containers

The table shows you the constructors and destructors of a container. A std:vector stands for the rest of them.

TypeExample
Defaultstd::vector<int> vec1
Rangestd::vector<int> vec2(vec1.begin(), vec1.end())
Copystd::vector<int> vec3(vec2)
Copystd::vector<int> vec3= vec2
Movestd::vector<int> vec4(std::move(vec3))
Movestd::vector<int> vec4= std::move(vec3)
Sequence (Initializer list)std::vector<int> vec5 {1, 2, 3, 4, 5}
Sequence (Initializer list)std::vector<int> vec5= {1, 2, 3, 4, 5}
  
Destructorvec5.~vector()
Delete elementsvec5.clear()

Because std::array is generated at compile time, there are a few things that are special. std::array has no move constructor and can neither be created with a range nor with an initialiser list. However, you can initialize a std::array with an aggregate initialisation. Also, std::array has no method for removing its elements.

#include <map>
#include <unordered_map>
#include <vector>
...
using namespace std;

vector<int> vec= {1, 2, 3, 4, 5, 6, 7, 8, 9};
map<string, int> m= {{"bart", 12345}, {"jenne", 34929}, {"huber", 840284} };
unordered_map<string, int> um{m.begin(), m.end()};

for (auto v: vec) cout << v << " "; // 1 2 3 4 5 6 7 8 9
for (auto p: m) cout << p.first << "," << p.second << " ";
                                    // bart,12345 huber,840284 jenne,34929
for (auto p: um) cout << p.first << "," << p.second << " ";
                                    // bart,12345 jenne,34929 huber,840284

vector<int> vec2= vec;
cout << vec.size() << endl; // 9
cout << vec2.size() << endl; // 9

vector<int> vec3= move(vec);
cout << vec.size() << endl; // 0
cout << vec3.size() << endl; // 9

vec3.clear();
cout << vec3.size() << endl; // 0

size+empty+max_size

#include <map>
#include <set>
#include <vector>
...
using namespace std;

vector<int> intVec{1, 2, 3, 4, 5, 6, 7, 8, 9};
map<string, int> str2Int = {{"bart", 12345}, 
                            {"jenne", 34929}, {"huber", 840284}};
set<double> douSet{3.14, 2.5};

cout << intVec.empty() << endl;  // false
cout << str2Int.empty() << endl; // false
cout << douSet.empty() << endl;  // false

cout << intVec.size() << endl;  // 9
cout << str2Int.size() << endl; // 3
cout << douSet.size() << endl;  // 2

cout << intVec.max_size() << endl;  // 4611686018427387903
cout << str2Int.max_size() << endl; // 384307168202282325
cout << douSet.max_size() << endl;  // 461168601842738790

std::copy

template<class InputIterator, class OutputIterator>
  OutputIterator copy (InputIterator first, InputIterator last, OutputIterator result)
{
  while (first!=last) {
    *result = *first;
    ++result; ++first;
  }
  return result;
}

access

IteratorDescription
cont.begin() and cont.end()Pair of iterators to iterate forward.
cont.cbegin() and cont.cend()Pair of iterators to iterate const forward.
cont.rbegin() and cont.rend()Pair of iterators to iterate backward.
cont.crbegin() and cont.crend()Pair of iterators to iterate const backward.

assign new elements
You can assign new elements to existing containers or swap two containers. For the assignment of a container cont2 to a container cont, there exists the copy assignment cont= cont2 and the move assignment cont= std::move(cont2). A special form of assignment is the one with an initialiser list: cont= {1, 2, 3, 4, 5}. That’s not possible for std::array, but you can instead use the aggregate initialisation. The function swap exists in two forms. You have it as a method cont(swap(cont2)) or as a function template std::swap(cont, cont2).

comparison operators
Containers support the comparison operators ==!=<><=>=. The comparison of two containers happens on the elements of the containers. If you compare associative containers, their key is compared. Unordered associative containers support only the comparison operator == and !=.

Sequential Container

Criteriaarrayvectordequelistforward_list
Sizestaticdynamicdynamicdynamicdynamic
Implementationstatic arraydynamic arraysequence of arraysdoubled linked listsingle linked list
Accessrandomrandomrandomforward and backwardforward
Optimized for insert and delete at end: O(1)begin and end: O(1)begin and end: O(1)begin(1)
    arbitrary: O(1)arbitrary: O(1)
Memory reservation yesnonono
Release of memory shrink_to_fitshrink_to_fitalwaysalways
Strengthno memory allocation; minimal memory requirements95% solutioninsertion and deletion at the begin and endinsertion and deletion at an arbitrary positionfast insertion and deletion; minimal memory requirements
Weaknessno dynamic memoryInsertion and deletionInsertion and deletionno random accessno random access
 memory allocationat an arbitrary position: O(n)at an arbitrary position: O(n)  
vector

std::vector is a homogeneous container, for which it’s length can be adjusted at runtime. std::vector needs the header <vector>. As it stores its elements contiguously in memory, std::vector support pointer arithmetic.

deque

std::deque, which consists of a sequence of arrays, is quite similar to std::vectorstd::deque need the header <deque>. The std::deque has three additional methods deq.push_front(elem)deq.pop_front() and `deq.emplace_front(args… ) to add or remove elements at its beginning.

list

std::list is a doubled linked list. std::list needs the header <list>.

Although it has a similar interface to std::vector or std::dequestd::list is quite different to both of them. That’s due to its structure.

Associative Container

Associative containerSortedAssociated valueMore identical keysAccess time
std::setyesnonologarithmic
std::unordered_setnononoconstant
std::mapyesyesnologarithmic
std::unordered_mapnoyesnoconstant
std::multisetyesnoyeslogarithmic
std::unordered_multisetnonoyesconstant
std::multimapyesyesyeslogarithmic
std::unordered_multimapnoyesyesconstant

Adaptors for Containers

stack

...
#include <stack>
...
std::stack<int> myStack;

std::cout << myStack.empty() << std::endl;   // true
std::cout << myStack.size() << std::endl;    // 0

myStack.push(1);
myStack.push(2);
myStack.push(3);
std::cout << myStack.top() << std::endl;     // 3

while (!myStack.empty()){ 
  std::cout << myStack.top() << " ";
  myStack.pop();
}                                            // 3 2 1

std::cout << myStack.empty() << std::endl;   // true
std::cout << myStack.size() << std::endl;    // 0

queue

...
#include <queue>
...
std::queue<int> myQueue;

std::cout << myQueue.empty() << std::endl;    // true
std::cout << myQueue.size() << std::endl;     // 0

myQueue.push(1);
myQueue.push(2);
myQueue.push(3);
std::cout << myQueue.back() << std::endl;     // 3
std::cout << myQueue.front() << std::endl;    // 1

while (!myQueue.empty()){
  std::cout << myQueue.back() << " ";
  std::cout << myQueue.front() << " : ";
  myQueue.pop();
}                                             // 3 1 : 3 2 : 3 3

std::cout << myQueue.empty() << std::endl;    // true
std::cout << myQueue.size() << std::endl;     // 0

priority_queue 

#include <queue>
...
std::priority_queue<int> myPriorityQueue;

std::cout << myPriorityQueue.empty() << std::endl;   // true
std::cout << myPriorityQueue.size() << std::endl;    // 0

myPriorityQueue.push(3);
myPriorityQueue.push(1);
myPriorityQueue.push(2);
std::cout << myPriorityQueue.top() << std::endl;     // 3

while (!myPriorityQueue.empty()){
  std::cout << myPriorityQueue.top() << " ";
  myPriorityQueue.pop();
}                                                    // 3 2 1

std::cout << myPriorityQueue.empty() << std::endl;   // true
std::cout << myPriorityQueue.size() << std::endl;    // 0

std::priority_queue<std::string, std::vector<std::string>,
                    std::greater<std::string>> myPriorityQueue2;

myPriorityQueue2.push("Only");
myPriorityQueue2.push("for");
myPriorityQueue2.push("testing");
myPriorityQueue2.push("purpose");
myPriorityQueue2.push(".");

while (!myPriorityQueue2.empty()){
  std::cout << myPriorityQueue2.top() << " ";
  myPriorityQueue2.pop();
}                                // . Only for purpose testing

back_inserter + front_inserter + inserter

#include <iterator>
...
std::deque<int> deq{5, 6, 7, 10, 11, 12};
std::vector<int> vec{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};

std::copy(std::find(vec.begin(), vec.end(), 13),
          vec.end(), std::back_inserter(deq));

for (auto d: deq) std::cout << d << " ";
                    // 5 6 7 10 11 12 13 14 15

std::copy(std::find(vec.begin(), vec.end(), 8),
std::find(vec.begin(), vec.end(), 10),
std::inserter(deq,
std::find(deq.begin(), deq.end(), 10)));d
for (auto d: deq) std::cout << d << " ";
                    // 5 6 7 8 9 10 11 12 13 14 15

std::copy(vec.rbegin()+11, vec.rend(),
std::front_inserter(deq));
for (auto d: deq) std::cout << d << " ";
                    // 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15