Post

C++ 11 Features

This are notes taking from videos in BoQian Channel, for learning purpose.

Initializer List

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//C++ 03 initializer list:
int arr[4] = {3, 2, 4, 5};

vector<int> v;
v.push_back(3);
v.push_back(2);
v.push_back(4);
v.push_back(5);

// C++ 11 extended the support 
vector<int> v = {3, 4, 1, 9};   // Calling initializer_list constructor
// All the relevant STL containers have been updated to accept initializer_list.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Define your own initializer_list constructor:
#include <initializer_list>
class BoVector {
   vector<int> m_vec;
   public:
   BoVector(const initializer_list<int>& v) {
      for (initializer_list<int>::iterator itr = v.begin(); itr!=v.end(); ++ itr)
         m_vec.push_back(*itr);
   }
};

BoVector v = {0, 2, 3, 4};
BoVector v{0, 2, 3, 4};   // effectively the same

Uniform Initialization

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// C++ 03
class Dog {     // Aggregate class or struct
   public:
      int age;
      string name;
};
Dog d1 = {5, "Henry"};   // Aggregate Initialization

// C++ 11 extended the scope of curly brace initialization
class Dog {
   public:
      Dog(int age, string name) {...};
};
Dog d1 = {5, "Henry"}; 

Uniform Initialization Search Order(Compiler):

  1. Initializer_list constructor
  2. Regular constructor that takes the appropriate parameters.
  3. Aggregate initializer.

Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Dog d1{3};

class Dog {
   public:
   int age;                                // 3rd choice

   Dog(int a) {                            // 2nd choice
      age = a;
   }

   Dog(const initializer_list<int>& vec) { // 1st choice
      age = *(vec.begin());      
   }
};

Auto Type

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
std::vector<int> vec = {2, 3, 4, 5};

// C++ 03
for (std::vector<int>::iterator it = vec.begin(); it!=vec.end(); ++ it)
    m_vec.push_back(*it);


// C++ 11: use auto type
for (auto it = vec.begin(); it!=vec.end(); ++ it)
    m_vec.push_back(*it);

auto a = 6;    // a is a integer
auto b = 9.6;  // b is a double
auto c = a;    // c is an integer

auto const x = a;   // int const x = a
auto& y = a;        // int& y = a

// It's static type, no run-time cost
// It also makes code easier to maintain.

// 1. Don't use auto when type conversion is needed
// 2. IDE becomes more important

foreach

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// C++ 03:
   for (vector<int>::iterator itr = v.begin(); itr!=v.end(); ++ itr)
      cout << (*itr);


// C++ 11:
   for (auto i: v) { // works on any class that has begin() and end()
      cout << i ;    // readonly access
   }

   for (auto& i: v) {
      i++;                 // changes the values in v
   }                       // and also avoids copy construction

   auto x = begin(v);  // Same as: int x = v.begin();

   int arr[4] = {3, 2, 4, 5};
   auto y = begin(arr); // y == 3
   auto z = end(arr);   // z == 5
   // How this worked? Because begin() and end() are defined for array.
   // Adapt your code to third party library by defining begin() and end()
   // for their containers.

nullptr

To replace NULL in C++ 03

1
2
3
4
5
6
7
8
9
void foo(int i) { cout << "foo_int" << endl; }
void foo(char* pc) { cout << "foo_char*" << endl; }

int main() {
   foo(NULL);    // Ambiguity

   // C++ 11
   foo(nullptr); // call foo(char*)
}

enum class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 // C++ 03
   enum apple {green_a, red_a};
   enum orange {big_o, small_o};
   apple a = green_a;
   orange o = big_o;

   if (a == o) 
      cout << "green apple and big orange are the same\n";
   else
      cout << "green apple and big orange are not the same\n";


   // C++ 11
   enum class apple {green, red};
   enum class orange {big, small};
   apple a = apple::green;
   orange o = orange::big;

   if (a == o) 
      cout << "green apple and big orange are the same\n";
   else
      cout << "green apple and big orange are not the same\n";

   // Compile fails because we haven't define ==(apple, orange)


static assert

1
2
3
4
5
// run-time assert
   assert( myPointer != NULL );

// Compile time assert (C++ 11)
   static_assert( sizeof(int) == 4 );

delegating constructor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// C++ 03:
class Dog {
   init() { ... };
   public:
   Dog() { init(); }
   Dog(int a) { init(); doOtherThings(); }
};
/* Cons:
 * 1. Cumbersome code.
 * 2. init() could be invoked by other functions.
 */

// C++ 11:
class Dog {
   int age = 9;
   public:
   Dog() { ... }
   Dog(int a) : Dog() { doOtherThings(); }
};
// Limitation: Dog() has to be called first.

constexpr

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int arr[6];    //OK
int A() { return 3; }
int arr[A()+3];   // Compile Error 

// C++ 11
constexpr int A() { return 3; }  // Forces the computation to happen 
                                 // at compile time.
int arr[A()+3];   // Create an array of size 6

// Write faster program with constexpr
constexpr int cubed(int x) { return x * x * x; }

int y = cubed(1789);  // computed at compile time

//Function cubed() is:
//1. Super fast. It will not consume run-time cycles
//2. Super small. It will not occupy space in binary.


New string literals

1
2
3
4
5
6
7
8
9
10
 // C++ 03:
  char*     a = "string";  

  // C++ 11:
  char*     a = u8"string";  // to define an UTF-8 string. 
  char16_t* b = u"string";   // to define an UTF-16 string. 
  char32_t* c = U"string";   // to define an UTF-32 string. 
  char*     d = R"string \\"    // to define raw string. 


Keyword final

1
2
3
4
5
6
7
class Dog final {    // no class can be derived from Dog
   ...
};
   
class Dog {
   virtual void bark() final;  // No class can override bark() 
};

Keyword delete

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Dog {
   Dog(int age) {}
}

Dog a(2);
Dog b(3.0); // 3.0 is converted from double to int
a = b;     // Compiler generated assignment operator

// preventing the user from using a class different manner
// C++ 11:
class Dog {
   Dog(int age) {}
   Dog(double ) = delete; //
   Dog& operator=(const Dog&) = delete;
}

Keyword default (for default constructor)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Dog {
   Dog(int age) {}
};

Dog d1;  // Error: compiler will not generate the default constructor


// C++ 11:
class Dog {
   Dog(int age);
   Dog() = default;    // Force compiler to generate the default constructor
};


Keyword override (for virtual function)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// C++ 03
class Dog {
   virtual void A(int);
   virtual void B() const;
}

class Yellowdog : public Dog {
   virtual void A(float);  // Created a new function
   virtual void B(); // Created a new function 
}


// C++ 11
class Dog {
   virtual void A(int);
   virtual void B() const;
   void C();
}

class Yellowdog : public Dog {
   virtual void A(float) override;  // Error: no function to override
   virtual void B() override;       // Error: no function to override
   void C() override;               // Error: not a virtual function
}


Lambda Function

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
cout << [](int x, int y){return x+y}(3,4) << endl;  // Output: 7
auto f = [](int x, int y) { return x+y; };
cout << f(3,4) << endl;   // Output: 7


template<typename func>
void filter(func f, vector<int> arr) {
   for (auto i: arr) {
      if (f(i))
         cout << i << " ";
   }
}

int main() {
   vector<int> v = {1, 2, 3, 4, 5, 6 };

   filter([](int x) {return (x>3);},  v);    // Output: 4 5 6
   ...
   filter([](int x) {return (x>2 && x<5);},  v); // Output: 3 4


   int y = 4;  
   filter([&](int x) {return (x>y);},  v);    // Output: 5 6
   //Note: [&] tells compiler that we want variable capture
}

// Lambda function works almost like a language extention
template
for_nth_item

This post is licensed under CC BY 4.0 by the author.