STL additions
Uniform initialization syntax 
Move semantic 
New methods 
New containers 
std::tuple
Very common code: 
for (set<boost::shared_ptr<Thread> >::const_iterator thread = 
clientThreads.begin(); 
thread != clientThreads.end(); thread++) 
{/* ... */} 
Allow compiler to deduce type: 
for (auto thread = clientThreads.begin(); 
thread != clientThreads.end(); ++thread) 
{/* ... */}
Simplify iteration for standard containers: 
int v[] { 1, -4, 11 }; 
for (int& i: v) { // for ( auto& i : v ) 
i += 42; 
} 
for (int i: v) { // for ( auto i : v ) 
cout << i << " "; 
} 
Output: 
43 38 53
Problem 
• C++ offers several ways of initializing an object depending on its 
type and the initialization context 
string a[] = { "foo", " bar" }; // ok: initialize array variable 
vector<string> v = { "foo", " bar" }; // error: initializer list for non-aggregate 
vector 
void f(string a[]); 
f( { "foo", " bar" } ); // syntax error: block as argument 
int a = 2; // ``assignment style'' 
int aa[] = { 2, 3 }; // assignment style with list 
complex z(1,2); // ``functional style'' initialization 
x = Ptr(y); // ``functional style'' for conversion/cast/construction 
int a(1); // variable definition 
int b(); // function declaration 
int b(foo); // variable definition or function declaration 
class Bar; 
int foo(Bar()); //function declaration !!!!
The C++11 solution is to allow {}-initializer lists for all initialization 
• aggregate initialization (POD, arrays, simple class) 
class Point { 
public: 
int x; 
int y; 
}; 
struct S { 
int x; 
struct Foo { 
int i; 
int j; 
int a[3]; 
} b; 
}; 
Point p1 = { 1, 2 }; // simple case 
Point p2{ 1, 2 }; 
S s1 = { 1, { 2, 3, {4, 5, 6} } }; 
S s3{1, {2, 3, {4, 5, 6} } }; // same, using direct-list-initialization syntax 
int ar[] = {1,2,3}; // ar is int[3] 
char cr[3] = {'a'}; // array initialized as {'a', '0', '0'} 
int ar2d1[2][2] = {{1, 2}, {3, 4}}; // fully-braced 2D array: {1, 2} 
// {3, 4}
• instead of () for constructors 
class MyClass { 
public: 
MyClass(double a, std::string str); 
MyClass(int k); 
MyClass(); 
} 
MyClass m1{1.0, "test"}; 
MyClass m2{1}; 
MyClass m3{};
• std::initializer_list<T> constructor 
#include <initializer_list> 
class Summator { 
public: 
Summator(std::initializer_list<int> il) { 
sum = 0; 
cout << il.size() << endl; 
for (auto i : il) { //for (const int* it = il.begin(); it != il.end(); it++ ) { 
cout << i << endl; // cout << *it << endl; 
sum += i; // sum += *it; 
} 
} 
int Get() { return sum; } 
private: 
int sum; 
}; 
Summator s1 { 1, 2, 3, 4, 5}; 
int i, j, k; 
//set i, j, k 
Summator s2 { i, j, k};
• All STL containers support std::initializer_list<T> 
constructor 
std::vector<int> v { 1, 2, 3, 4, 5}; 
std::string s1{'a', 'b', 'c', 'd'}; 
std::vector<Point> p { {i, j}, {j, i}, {i, i} }; 
std::map<int, std::string> m { 
{ 1, "string 1"}, 
{ 2, "string 2"}, 
{ 3, "string 3"}, 
};
Initializer list in range loop 
std::vector<int> v { 1, i , 2, j , 3, k} ; 
for (int x : {2, 4, 1}) 
{ 
std::cout << v[x] << " "; 
}
Importantly, T{a} constructs the same 
value in every context, so that {}- 
initialization gives the same result in all 
places where it is legal. 
T x{a}; 
T* p = new T{a}; 
z = T{a}; // use as cast 
f({a}); // function argument (of type T). 
return {T}; // function return value (function returning T)
Priority of constructors 
• If the braced-init-list is empty and T is a class type 
with a default constructor, value-initialization is 
performed (default constructor or 0) 
• Otherwise, if T is an aggregate type, aggregate 
initialization is performed (POD, array) 
• std::initializer_list constructor 
• Other constructors
Special cases 
//two constructors 
explicit vector (size_type n); // 1 
vector(initializer_list<value_type> l); // 2 
std::vector<int> v(100); //1: vector with 100 elements 
std::vector<int> v{100}; //2: vector with one element "100" 
std::vector<string> d {100}; //1: vector with 100 elements
C++ C++11 
std::vector<int> v; 
v.push_back(1); 
v.push_back(i); 
v.push_back(2); 
v.push_back(j); 
std::vector<int> v { 1, i, 2, j}; 
std::map<int, std::string> m; 
mymap.insert(std::pair<int,string>(1,"a")); 
mymap.insert(std::pair<int,string>(2,“b")); 
mymap.insert(std::pair<int,string>(3,“c“)); 
std::map<int, std::string> m = { 
{1, "a"}, 
{2, "b"}, 
{3, "c"} 
}; 
void Foo( std::set<MyClass>& c) { 
c.insert(MyClass(1, 1)); 
c.insert(MyClass(1.0, str)); 
} 
void Foo( std::set<MyClass>& c) { 
c.insert( {1,1} ); 
c.insert( {1.0, str} ); 
} 
Point GetCenterPoint() { 
//logic 
return Point(1,0); 
} 
Point GetCenterPoint() { 
//logic 
return {1, 0}; 
}
Temporary and non-temporary object 
• C++ works with temporary and non-temporary 
objects in the same way. 
std::vector<int> GetV(); 
int main() 
{ 
std::vector<int> v= GetV(); //functions return temporary object 
std::vector<string> sv; 
sv.push_back("string"); // temporary object std::string 
std::vector<Point> vp; 
vp.push_back({1,0}); //temporary object Point 
}
C++11 introduce rvalue reference ( T&&) 
• rvalue references enable compiler to distinguish an 
lvalue from an rvalue. ( separate temporary object and 
non-temporary object) 
• Move constructor and move assignment operator 
In some cases compiler generates automatically 
• Provide performance benefits to existing code 
without needing to make any changes outside the 
standard library. 
• All STL containers support move semantic
C++ 
C++11
Compile the same code with –std=c++11 
std::vector<int> GetV(); 
int main() 
{ 
std::vector<int> v= GetV(); //optimized (copy only pointer) 
std::vector<string> sv; 
sv.push_back("string"); // optimized 
std::vector<Point> vp; 
vp.push_back({1,0}); //no optimizing (point is simple struct) 
}
std::move 
• Force compiler to work with object as with 
temporary object ( cast to rvalue ) 
std::string str = "Hello"; 
std::vector<std::string> v; 
// uses the push_back(const T&) overload, which means 
// we'll incur the cost of copying str 
v.push_back(str); 
// uses the rvalue reference push_back(T&&) overload, 
// which means no strings will be copied; instead, the contents 
// of str will be moved into the vector. This is less 
// expensive, but also means str might now have unpredictable data. 
v.push_back(std::move(str));
class Buffer { 
char* _data; 
size_t _size; 
// ... 
// copy the content from lvalue 
Buffer(Buffer const& lvalue) 
: _data(nullptr), _size(0) 
{ 
// perform deep copy memcpy... 
} 
// take the internals from rvalue 
Buffer(Buffer&& rvalue) 
: _data(nullptr), _size(0) 
{ 
swap(_size, rvalue._size); 
swap(_data, rvalue._data); 
// it is vital to keep rvalue 
// in a consistent state 
} 
// ... 
Buffer getData() { /*...*/ } 
~Buffer() 
{ 
delete _data; 
} 
// ... 
Buffer someData; 
// ... initialize someData 
Buffer someDataCopy(someData); 
// make a copy 
Buffer anotherData(getData()); 
// move temporary
Emplace – series of STL container’s methods for 
inserting a new element to container. (emplace_back, 
emplace_front, emplace) 
• The element is constructed in-place, i.e. no copy operations are 
performed. 
• The constructor of the new element is called with exactly the 
same arguments as supplied to emplace
class TraceClass { 
public: 
TraceClass(std::string str, int dummy) : _str(str) { 
cout<< "constructing " << _str << endl; 
} 
TraceClass(const TraceClass& m): _str(m._str+ " copy") { 
cout << "copy " << m._str << endl; 
} 
~TraceClass() { 
cout << "destructing " << _str << endl; 
} 
private: 
std::string _str; 
}; 
std::vector<TraceClass> v; 
push_back emplace_back 
v.push_back(TraceClass("push_back_object“, 0)); v.emplace_back(“emplace_back_object“, 1);
T& std::map::at(const key_type& k) 
const T& std::map::at(const key_type& k) const 
• Returns a reference to the mapped value of the 
element identified with key k. 
• If k does not match the key of any element in the 
container, the function throws an out_of_range 
exception.
T* std::vector::data(); 
const T* std::vector::data() const; 
• Returns pointer to the underlying array serving as 
element storage.
forward_list<T> 
• single linked list 
array – implements built-in array with STL-like 
interface: 
• operator==,!=,<,<=,>,>= , operator= 
• front(), back() 
• at 
#include <array> 
array<int, 3> GetArr() 
{ 
return array<int, 3>{ 0x5, 0xFF, 0x32 }; 
// return { { 0x5, 0xFF, 0x32 } }; 
}
unordered_set<T>, unordered_map<T>, 
unordered_multiset<T>, 
unordered_multimap<T> 
• variations of hash tables 
• Search, insertion, and removal have average 
constant-time complexity. 
#include <unordered_map> 
struct my_data {}; 
unordered_map<string, my_data, hash<string>> data_table;
std::tuple is a fixed-size collection of heterogeneous 
values. It is a generalization of std::pair. 
tuple<int, std::string, int> t1(1, "abc", 1);  
int a = get<0>(t1); 
string b = get<1>(t1); 
string b2 = get<string>(t1); // since C++14 
int a = get<int>(t1); // error 
tuple <int, const char*, int> t0 (5, "test",3 ); 
t1 = t0; 
get<0>(t1) = 0; 
cout << ( t0 > t1) << endl; // true 
map<tuple <int, const char*, int>, double> m;
make_tuple creates a tuple object of the 
type defined by the argument types 
auto t1 = make_tuple(10, "Test", 3.14); 
int n = 1; 
auto t2 = make_tuple(ref(n), n); 
n = 7; 
cout << "The value of t2 is " << "(" 
<< get<0>(t2) << ", " << get<1>(t2) << ")n"; 
// The value of t2 is (7, 1) 
tuple_cat сonstructs a tuple that is a 
concatenation of all tuples in args 
tuple<int, std::string, float> t1(10, "Test", 3.14); 
auto t2 = tuple_cat(t1, make_pair("Foo", "bar"), t1);
tuple_size<tuple_type>::value obtains 
the size of tuple at compile time 
tuple_element obtains the type of the 
specified element 
template <class... Args> 
struct type_list 
{ 
template <std::size_t N> 
using type = typename std::tuple_element<N, std::tuple<Args...>>::type; 
}; 
int main() 
{ 
type_list<int, char, bool>::type<2> x = true; 
} 
tuple_size< tuple<int,double,float> >::value
std::tie creates a tuple of lvalue references to its 
arguments or instances of std::ignore. 
struct S { 
int n; 
std::string s; 
float d; 
bool operator<(const S& rhs) const { 
// compares n to rhs.n, 
// then s to rhs.s, 
// then d to rhs.d 
return std::tie(n, s, d) < std::tie(rhs.n, rhs.s, rhs.d); 
} 
}; 
int main() { 
std::set<S> set_of_s; // S is LessThanComparable 
S value{42, "Test", 3.14}; 
bool inserted; 
// unpacks the return value of insert into iter and inserted 
tie(ignore, inserted) = set_of_s.insert(value); 
// pair<set<S>::iterator, bool> = set_of_s.insert(value); 
}
tuple<int, string, double> Get(int a) { 
return make_tuple(a*5, string(a, 'c'), 1.1*a); 
} 
int i; string str; 
tie(i, str, ignore) = Get(32);
C++11 - STL Additions

C++11 - STL Additions

  • 1.
  • 2.
    Uniform initialization syntax Move semantic New methods New containers std::tuple
  • 3.
    Very common code: for (set<boost::shared_ptr<Thread> >::const_iterator thread = clientThreads.begin(); thread != clientThreads.end(); thread++) {/* ... */} Allow compiler to deduce type: for (auto thread = clientThreads.begin(); thread != clientThreads.end(); ++thread) {/* ... */}
  • 4.
    Simplify iteration forstandard containers: int v[] { 1, -4, 11 }; for (int& i: v) { // for ( auto& i : v ) i += 42; } for (int i: v) { // for ( auto i : v ) cout << i << " "; } Output: 43 38 53
  • 5.
    Problem • C++offers several ways of initializing an object depending on its type and the initialization context string a[] = { "foo", " bar" }; // ok: initialize array variable vector<string> v = { "foo", " bar" }; // error: initializer list for non-aggregate vector void f(string a[]); f( { "foo", " bar" } ); // syntax error: block as argument int a = 2; // ``assignment style'' int aa[] = { 2, 3 }; // assignment style with list complex z(1,2); // ``functional style'' initialization x = Ptr(y); // ``functional style'' for conversion/cast/construction int a(1); // variable definition int b(); // function declaration int b(foo); // variable definition or function declaration class Bar; int foo(Bar()); //function declaration !!!!
  • 6.
    The C++11 solutionis to allow {}-initializer lists for all initialization • aggregate initialization (POD, arrays, simple class) class Point { public: int x; int y; }; struct S { int x; struct Foo { int i; int j; int a[3]; } b; }; Point p1 = { 1, 2 }; // simple case Point p2{ 1, 2 }; S s1 = { 1, { 2, 3, {4, 5, 6} } }; S s3{1, {2, 3, {4, 5, 6} } }; // same, using direct-list-initialization syntax int ar[] = {1,2,3}; // ar is int[3] char cr[3] = {'a'}; // array initialized as {'a', '0', '0'} int ar2d1[2][2] = {{1, 2}, {3, 4}}; // fully-braced 2D array: {1, 2} // {3, 4}
  • 7.
    • instead of() for constructors class MyClass { public: MyClass(double a, std::string str); MyClass(int k); MyClass(); } MyClass m1{1.0, "test"}; MyClass m2{1}; MyClass m3{};
  • 8.
    • std::initializer_list<T> constructor #include <initializer_list> class Summator { public: Summator(std::initializer_list<int> il) { sum = 0; cout << il.size() << endl; for (auto i : il) { //for (const int* it = il.begin(); it != il.end(); it++ ) { cout << i << endl; // cout << *it << endl; sum += i; // sum += *it; } } int Get() { return sum; } private: int sum; }; Summator s1 { 1, 2, 3, 4, 5}; int i, j, k; //set i, j, k Summator s2 { i, j, k};
  • 9.
    • All STLcontainers support std::initializer_list<T> constructor std::vector<int> v { 1, 2, 3, 4, 5}; std::string s1{'a', 'b', 'c', 'd'}; std::vector<Point> p { {i, j}, {j, i}, {i, i} }; std::map<int, std::string> m { { 1, "string 1"}, { 2, "string 2"}, { 3, "string 3"}, };
  • 10.
    Initializer list inrange loop std::vector<int> v { 1, i , 2, j , 3, k} ; for (int x : {2, 4, 1}) { std::cout << v[x] << " "; }
  • 11.
    Importantly, T{a} constructsthe same value in every context, so that {}- initialization gives the same result in all places where it is legal. T x{a}; T* p = new T{a}; z = T{a}; // use as cast f({a}); // function argument (of type T). return {T}; // function return value (function returning T)
  • 12.
    Priority of constructors • If the braced-init-list is empty and T is a class type with a default constructor, value-initialization is performed (default constructor or 0) • Otherwise, if T is an aggregate type, aggregate initialization is performed (POD, array) • std::initializer_list constructor • Other constructors
  • 13.
    Special cases //twoconstructors explicit vector (size_type n); // 1 vector(initializer_list<value_type> l); // 2 std::vector<int> v(100); //1: vector with 100 elements std::vector<int> v{100}; //2: vector with one element "100" std::vector<string> d {100}; //1: vector with 100 elements
  • 14.
    C++ C++11 std::vector<int>v; v.push_back(1); v.push_back(i); v.push_back(2); v.push_back(j); std::vector<int> v { 1, i, 2, j}; std::map<int, std::string> m; mymap.insert(std::pair<int,string>(1,"a")); mymap.insert(std::pair<int,string>(2,“b")); mymap.insert(std::pair<int,string>(3,“c“)); std::map<int, std::string> m = { {1, "a"}, {2, "b"}, {3, "c"} }; void Foo( std::set<MyClass>& c) { c.insert(MyClass(1, 1)); c.insert(MyClass(1.0, str)); } void Foo( std::set<MyClass>& c) { c.insert( {1,1} ); c.insert( {1.0, str} ); } Point GetCenterPoint() { //logic return Point(1,0); } Point GetCenterPoint() { //logic return {1, 0}; }
  • 15.
    Temporary and non-temporaryobject • C++ works with temporary and non-temporary objects in the same way. std::vector<int> GetV(); int main() { std::vector<int> v= GetV(); //functions return temporary object std::vector<string> sv; sv.push_back("string"); // temporary object std::string std::vector<Point> vp; vp.push_back({1,0}); //temporary object Point }
  • 16.
    C++11 introduce rvaluereference ( T&&) • rvalue references enable compiler to distinguish an lvalue from an rvalue. ( separate temporary object and non-temporary object) • Move constructor and move assignment operator In some cases compiler generates automatically • Provide performance benefits to existing code without needing to make any changes outside the standard library. • All STL containers support move semantic
  • 17.
  • 18.
    Compile the samecode with –std=c++11 std::vector<int> GetV(); int main() { std::vector<int> v= GetV(); //optimized (copy only pointer) std::vector<string> sv; sv.push_back("string"); // optimized std::vector<Point> vp; vp.push_back({1,0}); //no optimizing (point is simple struct) }
  • 19.
    std::move • Forcecompiler to work with object as with temporary object ( cast to rvalue ) std::string str = "Hello"; std::vector<std::string> v; // uses the push_back(const T&) overload, which means // we'll incur the cost of copying str v.push_back(str); // uses the rvalue reference push_back(T&&) overload, // which means no strings will be copied; instead, the contents // of str will be moved into the vector. This is less // expensive, but also means str might now have unpredictable data. v.push_back(std::move(str));
  • 20.
    class Buffer { char* _data; size_t _size; // ... // copy the content from lvalue Buffer(Buffer const& lvalue) : _data(nullptr), _size(0) { // perform deep copy memcpy... } // take the internals from rvalue Buffer(Buffer&& rvalue) : _data(nullptr), _size(0) { swap(_size, rvalue._size); swap(_data, rvalue._data); // it is vital to keep rvalue // in a consistent state } // ... Buffer getData() { /*...*/ } ~Buffer() { delete _data; } // ... Buffer someData; // ... initialize someData Buffer someDataCopy(someData); // make a copy Buffer anotherData(getData()); // move temporary
  • 21.
    Emplace – seriesof STL container’s methods for inserting a new element to container. (emplace_back, emplace_front, emplace) • The element is constructed in-place, i.e. no copy operations are performed. • The constructor of the new element is called with exactly the same arguments as supplied to emplace
  • 22.
    class TraceClass { public: TraceClass(std::string str, int dummy) : _str(str) { cout<< "constructing " << _str << endl; } TraceClass(const TraceClass& m): _str(m._str+ " copy") { cout << "copy " << m._str << endl; } ~TraceClass() { cout << "destructing " << _str << endl; } private: std::string _str; }; std::vector<TraceClass> v; push_back emplace_back v.push_back(TraceClass("push_back_object“, 0)); v.emplace_back(“emplace_back_object“, 1);
  • 23.
    T& std::map::at(const key_type&k) const T& std::map::at(const key_type& k) const • Returns a reference to the mapped value of the element identified with key k. • If k does not match the key of any element in the container, the function throws an out_of_range exception.
  • 24.
    T* std::vector::data(); constT* std::vector::data() const; • Returns pointer to the underlying array serving as element storage.
  • 25.
    forward_list<T> • singlelinked list array – implements built-in array with STL-like interface: • operator==,!=,<,<=,>,>= , operator= • front(), back() • at #include <array> array<int, 3> GetArr() { return array<int, 3>{ 0x5, 0xFF, 0x32 }; // return { { 0x5, 0xFF, 0x32 } }; }
  • 26.
    unordered_set<T>, unordered_map<T>, unordered_multiset<T>, unordered_multimap<T> • variations of hash tables • Search, insertion, and removal have average constant-time complexity. #include <unordered_map> struct my_data {}; unordered_map<string, my_data, hash<string>> data_table;
  • 27.
    std::tuple is afixed-size collection of heterogeneous values. It is a generalization of std::pair. tuple<int, std::string, int> t1(1, "abc", 1); int a = get<0>(t1); string b = get<1>(t1); string b2 = get<string>(t1); // since C++14 int a = get<int>(t1); // error tuple <int, const char*, int> t0 (5, "test",3 ); t1 = t0; get<0>(t1) = 0; cout << ( t0 > t1) << endl; // true map<tuple <int, const char*, int>, double> m;
  • 28.
    make_tuple creates atuple object of the type defined by the argument types auto t1 = make_tuple(10, "Test", 3.14); int n = 1; auto t2 = make_tuple(ref(n), n); n = 7; cout << "The value of t2 is " << "(" << get<0>(t2) << ", " << get<1>(t2) << ")n"; // The value of t2 is (7, 1) tuple_cat сonstructs a tuple that is a concatenation of all tuples in args tuple<int, std::string, float> t1(10, "Test", 3.14); auto t2 = tuple_cat(t1, make_pair("Foo", "bar"), t1);
  • 29.
    tuple_size<tuple_type>::value obtains thesize of tuple at compile time tuple_element obtains the type of the specified element template <class... Args> struct type_list { template <std::size_t N> using type = typename std::tuple_element<N, std::tuple<Args...>>::type; }; int main() { type_list<int, char, bool>::type<2> x = true; } tuple_size< tuple<int,double,float> >::value
  • 30.
    std::tie creates atuple of lvalue references to its arguments or instances of std::ignore. struct S { int n; std::string s; float d; bool operator<(const S& rhs) const { // compares n to rhs.n, // then s to rhs.s, // then d to rhs.d return std::tie(n, s, d) < std::tie(rhs.n, rhs.s, rhs.d); } }; int main() { std::set<S> set_of_s; // S is LessThanComparable S value{42, "Test", 3.14}; bool inserted; // unpacks the return value of insert into iter and inserted tie(ignore, inserted) = set_of_s.insert(value); // pair<set<S>::iterator, bool> = set_of_s.insert(value); }
  • 31.
    tuple<int, string, double>Get(int a) { return make_tuple(a*5, string(a, 'c'), 1.1*a); } int i; string str; tie(i, str, ignore) = Get(32);

Editor's Notes

  • #21 Consider a buffer class: Old good copy constructor – makes a deep copy. Move constructor – takes resources from its argument: Special syntax for identify rvalue Must keep rvalue object in the consistent state