STL11 Sven Johannsen

09.11.2013

Meeting C++ Düsseldorf sven@sven-johannsen.de

www.sven-johannsen.de

@svenjohannsen



Content Motivation

History

What's new in the STL? Initializer list support R-Value support STL changes (Containers, Iterators, Algorithms) New (non STL) Libraries

Questions

Motivation A short example for the erase-remove idiom C++ 98/03 vector<int> v; v.push_back(0); v.push_back(5); v.push_back(2); v.push_back(3); // use the erase-remove idiom to remove all elements with the value 5 v.erase(remove(v.begin(), v.end(), 5)); v = vector<int>(v.begin(), v.end()); // free unused capacity C++ 11 vector<int> v = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; // vector<int> v(10); iota(begin(v), end(v), 0); // use the erase-remove idiom to remove all elements with the value 5 v.erase(remove(begin(v), end(v), 5)); v.shrink_to_fit(); // free unused capacity

History (STL) C++98 / C++03 vector, list, ...

iterators

algorithm

string

iostream

... C++11 Language change R-Values / Move semantic

uniform initialization TR1 (2005) boost subset

unordered container

random

C99 header wrapper C++11 Standard library concurrency

unique_ptr

exception

forward_list

extend algorithm

non-member begin() / end() Boost Subset 1 (2000-...) shared_ptr

tuple

array

function, bind, mem_fn, ref, result_of Boost Subset 2 (Thread)

(scoped_ptr)

(exception)

What's new in the STL? Initializer lists

R-value references

Container 6 new container (1 post TR1) some smaller enhancements

Iterator non-member begin and end

Algorithms 18 new algorithms

Outside the STL smart pointer ratio & chrono tuple



Uniformed initialization Problem: Different syntaxes for initializing struct A { int i; int j; }; struct B { B(int ii, int jj); /* ... */ }; C++98 A a = { 1, 3 }; B b(1, 3); C++11 Uniform initialization (N2532) // Aggregates (e.g. arrays and structs): A a1 = { 1, 3 }; // Initialize members from begin-to-end // Non-aggregates: Invoke a constructor. B b1 = { 1, 3 }; // alternative syntax A a2 { 1, 3 }; B b2 { 1, 3 };

Uniformed initialization for containers C++98 int arr[] = {1, 2, 3}; vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); C++11 Initializer Lists (N2672) #include <initializer_list> template <class T> // ignoring allocators class vector { // ... vector(initializer_list<T>); // initializer list constructor vector(size_type n, const T& value); // other constructor //... }; vector<int> vec1 = { 10, 2 }; // vector::vector(initializer_list<T>); vector<int> vec2(10, -1); // vector::vector(size_type n, const T& value);

STL & Initializer Lists All STL containers support uniformed initialization vector<int> v({ 2, 3, 5, 7, 11, 13, 17 }); list<int> l = { 0, 1, 2, 3, 4, 5, 6 }; map<int, string> m { { 1, "one" }, { 2, "two" } }; valarray<double> v = { 1.0, 0.1, 0.001, 0.0001 }; // same for deque, forward_list, set, string, regex // unordered_map, unordered_set, multi_.. // but not for: queue, priority_queue and stack // aggregate initialization array<double,4> a = { 1.0, 0.1, 0.001, 0.0001 }; and some algorithms too min, max, minmax

some random devices (seed_seq, discrete_distribution, ...)

More than initialization Most containers overload some additional member functions for initializer_list<T>. vector<int> v = { -1, -2, -3 }; // v = -1, -2, -3 v = { 1, 2, 3 }; // operator=() v = 1, 2, 3 v.insert(end(v), { 4, 5, 6 }); // v = 1,2,3,4,5,6 v.assign({ -1, -2, -3 }); // v = -1, -2, -3 constructor, operator=, insert (all STL containers)

assign (string, deque, forward_list, list, vector)

append (string)

replace (string)

operator+= (string) (All STL containers = { string , deque , forward_list ( insert_after() ), list , vector , map , multimap , set , multiset , unordered_map , unordered_multimap , unordered_set , unordered_multiset })

Class initializer_list<class E> #include <initializer_list> ... template<class E> class initializer_list { public: // some typedefs initializer_list() noexcept; // default constructor size_t size() const noexcept; // number of elements const E* begin() const noexcept; // first element const E* end() const noexcept; // one past the last element }; Only the compiler should fill the Initializer Lists. initializer_list<string> strings = { "C++", "is", "cool!" };

Using the Initializer lists Using the class initializer_list in user defined containers template<class T> MyVector<T>::MyVector(initializer_list<T> i_list) { reserve(i_list.size()); for(auto iter = i_list.begin(); iter != i_list.end(); ++iter) push_back(*elem); // for(const auto& T elem : i_list) // push_back(elem); } // usage MyVector<int> v = { 2, 3, 5, 7 };

Compile time container initializer_list is not limited to container void print_some_doubles(initializer_list<double> doubles) { for(double d : doubles) cout << d << " "; } ... print_some_doubles({ 1, 2, 3 });

R-Value References support in the STL Problem: Performance! Copy semantic can result in performance issues. vector<string> v; v.push_back("C++"); v.push_back("Boost"); // Hint: emplace_back beats move semantic C++11 introduce move semantic into the language to reduce the number of new / delete calls. Temporary objects ("objects without a name"): implicit conversions

function return values

nested operations ( a+b+c )

Move Semantic How to move? Detect temporary objects (r-values) basic_string& operator=(const basic_string& str); // l-value reference basic_string& operator=(basic_string&& str) noexcept; // r-value reference Steal the content from the temporary object Bring the temporary objects in a stable state Designed for objects which uses of dynamic memory, like STL containers Looks like moving the objects, but only the content is moving

R-Value References everywhere Addional overloads for r-value references vector: constructors vector(vector&&);

assignment operator= (vector<T,Allocator>&& );

add void push_back(T&& x);

insert insert(const_iterator position, T&& x); vector<string> v; string text("C++"); v.push_back(text); // copy "C++" v.push_back("Use the boost library!"); // create a temp. string object STL overloads many functions for improving the performance.

E.g. 12 different operator+() for the combination of string& , string&& and char*

Enforce moving The C++ and the STL "moves" only temporary objects ("objects without a name") To move non-temporary objects, use std::move() to mark an object as r-value reference. vector<int> temp = { 1, 2, 3 }; vector<int> result = { }; result = std::move(temp); //result = static_cast<vector<int>&& >(temp); assert(temp.size() == 0); assert(result.size() == 3); assert(result[0] == 1 && result[1] == 2 && result[2] == 3);

Move non-copyable objects Examples: file streams (ifstream, ofstream)

unique_ptr (non copyable smartpointers) ifstream open_file(const string& filename) { ... } unique_ptr<MyDocument> document_factor(Param param) { ... } vector<unique_ptr<MyDocument>> documents; documents.push_back(document_factor(param));

Emplace (deque, list, vector, priority_queue) Construct an element in the container. Forward all parameters to the constructor. template <class... Args> void emplace_back(Args&&... args); template <class... Args> iterator emplace(const_iterator position, Args&&... args); Example: vector<string> field= { " " }; field.emplace_back("C++"); char* text = "Hallo"; field.emplace(field.begin(), text, text+6); // field == "Hello", " ", "C++"

Containers TR1 array

4 Unordered associative containers (hash tables)

unordered_map, unordered_multimap, unordered_set, unordered_multiset C++ 11 forward_list Changes for exiting containers cbegin() & cend()

shrink_to_fit()

data()

map::at()

array As efficient as a "C style" array, but with the interface of a STL container compile time size

at the stack (or with the object)

most efficient container (for fixes sizes) int field[3] = { 1, 2, 3 }; array<int, 3> arr = { 1, 2, 3 }; cout << "size : " << arr.size() << endl; for (auto it = arr.begin(); it != arr.end(); ++it) cout << *it << " "; cout << endl;

array template <class T, size_t N> struct array { // some typedefs // no constructor, no operator=() ! void fill(const T& u); iterator begin() noexcept; iterator end() noexcept; // rbegin(), rend(), cbegin(), cend(), crbegin(), crend() constexpr size_type size() noexcept; // max_size, empty reference operator[](size_type n); reference at(size_type n); reference front(); reference back(); T* data() noexcept; // plus const functions };

Examples array<int, 3> arr {}; // zero initialization arr.fill(-11); for (auto i : arr) assert(i == -11); iota(arr.begin(), arr.end(), 1); int i = arr[0]; int j = arr.at(1); int k = arr.back(); // last element assert(i = 1 && j == 2 && k == 3); int l = arr.at(10); // will throw an "out of range" exception

Unordered associative containers 4 new hash_maps (associative containers): unordered_map,

unordered_multimap,

unordered_set and

unordered_multiset. Similar to map , multimap , set and unordered_multiset , with different requirements for the key and different storage. The naming tries to avoid breaking existing code.

Unordered associative containers replacement map<string, int> index = { { "C++", 1 }, { "Boost", 42 } }; unordered_map<string, int> fast_index = { { "C++", 1 }, { "Boost", 42 } };

Unordered associative containers Hash and equality requirement for the key map<string, int> index; // same as: map<string, int, less<string> > index; struct PersonLess { bool operator()(const Person& l, const Person& r) { return l.Name() < r.Name(); } }; map<Person, Account, PersonLess> AccountInfo;

Unordered associative containers Requirements for the key unordered_map<string, int> fast_index; // same as: unordered_map<string, int, hash<string>, equal_to<string> > fast_index; struct PersonHash { size_t operator()(const Person& p) { return hash<string>()(p.Name()); } }; // for the case of collitions struct PersonEquality { bool operator()(const Person& l, const Person& r) { return l.Name() == r.Name(); } }; unordered_map<Person, Account, PersonHash, PersonEquality> FastAccountInfo;

Unordered associative containers Predefined hash functions Hash functions are available for build-ins (bool, int, float, T*, ...),

strings, (std::string, std::wstring)

smart pointers,

std::vector<bool>,

std::bitset,

std::thread::id,

std::error_code,

std::type_index

forward_list Minimal list implementation, which avoid expensive operations (e.g. back() ). only forward iteration

many *_after() functions

functions no access to the end: back() , push_back() , ...

, , ... no size() function

function simple end()

forward_list template <class T, class Allocator = allocator<T> > class forward_list { public: // some typedefs explicit forward_list(); // 9 constructors forward_list& operator=(initializer_list<T>); // +3 iterator begin() noexcept; iterator end() noexcept; // + cbegin, ... but no rbegin() bool empty() const noexcept; // no size() void push_front(const T& x); void pop_front(); iterator insert_after(const_iterator position, const T& x); // + 5 // ... void sort(); void reverse() noexcept; };

insert_after() STL container member functions like insert() need the access to the prior element. insert_after()

erase_after()

splice_after()

Further Changes for exiting containers (a) const_iterator cbegin , cend , crbegin , crend const_iterator cbegin() const noexcept; const_iterator cend() const noexcept; Better control of the used iterator type void foo(const vector<int>& cv, vector<int>& ncv) { // C++98 for (vector<int>::const_iterator it1 = cv.begin(); it != cv.end(); ++it) {} for (vector<int>::const_iterator it2 = ncv.begin(); it != ncv.end(); ++it) {} // C++11 for (auto it = cv.begin(); it1 != cv.end(); ++it) {} // const_iterator for (auto it = ncv.begin(); it2 != ncv.end(); ++it) {} // iterator for (auto it = ncv.cbegin(); it3 != ncv.cend(); ++it) {} // const_iterator

Further Changes for exiting containers (b) capacity (string, deque, vector) void shrink_to_fit(); Ask for reducing capacity() to size() . Example: // free unused capacity with a temp. object vector<int> tmp(v.begin(), v.end()); v.swap(tmp); // free unused capacity v.shrink_to_fit();

Further Changes for exiting containers (c) data access (vector, array) T* data() noexcept; const T* data() const noexcept; Return the address of the first element. Example: vector<BYTE> field = ...; legacy_function(BYTE* raw_data, int size); ... // C++98: address of the first element legacy_function(field.empty() ? NULL : &field[0], field.size()); legacy_function(field.empty() ? NULL : &field.front(), field.size()); // C++11 use data legacy_function(field.data(), field.size());

Further Changes for exiting containers (d) map::at() Element access with range check (throws, if the key is not present). map<string, int> cont; int val; // C++ 98 val = cont["key"]; //(1) may add a default value to the map auto it = cont.find("key"); if(it != cont.end()) //(2) val = it->second; // C++11 val = map.at("key"); //(3) throws "out_of_range", if key not present

Iterators Range access non member begin() and end()

Non Member begin() and end() Unified iterator access for any container Addition level of abstraction for an iterator access. // vector<int> cont = { ... }; // int cont[] = { ... }; for(auto it = begin(cont); it != end(cont); ++it) { cout << *it << " "; } This code runs with any container (if non-member begin() and end() are overloaded). C++14 will also introduce non-member cbegin , cend , rbegin , rend , crbegin and crend .

New Algorithms A-M N-Z all_of (is p true for all e in R?) is_partitioned (is R partitioned per p?) any_of (is p true for any e in R?) partition_point (find first e in R where p(e) is false) none_of (is p true for no e in R?) is_sorted (is R sorted?) find_if_not (find first e in R where p is false) is_sorted_until (find first out-of-order e in R) copy_if (copy all e in R where p is true) is_heap (do elements in R form a heap?) copy_n (copy first n elements of R) is_heap_until (find first out-of-heap-ordered in R) iota (assign all e in R increasing values starting with v) move (like copy, but each e in R is moved) minmax (return pair(minVal, maxVal) for given inputs) move_backward (like copy_backward , but each e in R is moved) minmax_element (return pair(min_element, max_element) for R) partition_copy (copy all e in R to 1 of 2 destinations per p(e))

R is a range, e is an element, p is a predicate. (note: use <numeric> for iota )

std::string string to number

number to string

string to number conversion C++ wrapper around strtol(), ... int stoi(const string& str, size_t *idx = 0, int base = 10); long stol(const string& str, size_t *idx = 0, int base = 10); unsigned long stoul(const string& str, size_t *idx = 0, int base = 10); long long stoll(const string& str, size_t *idx = 0, int base = 10); unsigned long long stoull(const string& str, size_t *idx = 0, int base = 10); float stof(const string& str, size_t *idx = 0); double stod(const string& str, size_t *idx = 0); long double stold(const string& str, size_t *idx = 0); non-member functions

std::string and std::wstring

and may throw an exception ( std::invalid_argument , std::out_of_range )

number to string conversion and back into a string string to_string(int val); string to_string(unsigned val); string to_string(long val); string to_string(unsigned long val); string to_string(long long val); string to_string(unsigned long long val); string to_string(float val); string to_string(double val); string to_string(long double val); non-member functions

also to_wstring(...)

Examples stoi() string text{ "3E8" }; int val{}; try { size_t index; // no initialization needed, only output! val = stoi(text, &index, 16); } catch (const exception& ex) { cout << "Error : " << ex.what() << endl; } assert(val == 1000); to_string() wstring text = to_wstring(15); wcout << text << endl;

Smart-Pointers Memory management can be tricky void f() { // init std::string name("A . . . long . . . Name"); MyObject* p = new MyObject(15); OtherObject* q = getOtherObject("Bla"); try { maybeThrowing(p); // may throw an exception, will be handled outside otherFunction(q) } catch(...) { delete q; delete p; throw; } delete q; delete p; }

Smart-Pointers TR1 shared_ptr smart pointer with a shared ownership of an object

smart pointer with a shared ownership of an object weak_ptr weak reference to an object behind a shared_ptr C++11 unique_ptr very efficient smart pointer with move semantic

very efficient smart pointer with move semantic make_shared created the shared_ptr's control block and the object with one single memory allocation C++14 make_unique Enables the same syntax for unique_ptr as make_shared.

Smart-Pointers exception safety

prevent memory leaks shared_ptr very flexible

some notable costs (reference counting with concurrency support) unique_ptr most efficient smart pointer

move semantic STL container type function return type



unique_ptr C++98 C++11 MyObject* foo() { string name("A...long...Name"); MyObject* p = new MyObject(15); OtherObj* q = getOtherObj("Bla"); try { maybeThrowing(q); otherFunction(p) } catch(...) { delete q; delete p; throw; } delete q; return p; } shared_ptr<MyObject> foo() { string name("A...long...Name"); auto p = make_shared<MyObject>(15); unique_ptr<OtherObj> q(getOtherObj("Bla")); maybeThrowing(q.get()); otherFunction(p) return p; }

make_shared Create the created the shared_ptr's control block and the object with one single memory allocation. struct DBConnec { DBConnec(string dbname, string server, string securityInfo){} }; // TR1 shared_ptr<DBConnec> dbConn1(new DBConnec("southwind", "localhost", "SSPI")); // C++11 unique_ptr<DBConnec> dbConn2(new DBConnec("storm", "192.168.10.11", "none")); // make_shared (C++11) auto dbConn1 = make_shared<DBConnec>("southwind", "localhost", "SSPI"); // make_unique (C++14) auto dbConn2 = make_unique<DBConnec>("storm", "192.168.10.11", "none");

new Libraries Time utilities (chrono)

Compile-time rational arithmetic (ratio)

tuple

(atomic operations library)

(thread)

(regex) this_thread::sleep_for(std::chrono::milliseconds(123));

Compile-time rational arithmetic ratio A template class which exactly represents any finite rational number with a numerator and denominator representable by compile-time constants template <intmax_t N, intmax_t D = 1> class ratio { public: typedef ratio<num, den> type; static constexpr intmax_t num; static constexpr intmax_t den; };

ratio typedef ratio<1, 1000000000000000000000000> yocto; //see below typedef ratio<1, 1000000000000000000000> zepto; //see below typedef ratio<1, 1000000000000000000> atto; typedef ratio<1, 1000000000000000> femto; typedef ratio<1, 1000000000000> pico; typedef ratio<1, 1000000000> nano; typedef ratio<1, 1000000> micro; typedef ratio<1, 1000> milli; typedef ratio<1, 100> centi; typedef ratio<1, 10> deci; typedef ratio< 10, 1> deca; typedef ratio< 100, 1> hecto; typedef ratio< 1000, 1> kilo; typedef ratio< 1000000, 1> mega; typedef ratio< 1000000000, 1> giga; typedef ratio< 1000000000000, 1> tera; typedef ratio< 1000000000000000, 1> peta; typedef ratio< 1000000000000000000, 1> exa; typedef ratio< 1000000000000000000000, 1> zetta; //see below typedef ratio<1000000000000000000000000, 1> yotta; //see below

ratio Simple conversion of SI units template<class From, class To, class T> T convert(T from) { typedef ratio_divide<From, To> result; return from * result::num / result::den; } typedef ratio<1,1> base; typedef ratio<1760 * 3600, 3937> mile; cout << "2.0501 km as " << convert<kilo, base>(2.0501) << " m" << endl; // 2.0501 km as 2050.1 m cout << " 25.0 mm as " << convert<milli, base>(25.0) << " m" << endl; // 25.0 mm as 0.025m cout << " 25.0 mm as " << convert<milli, centi>(25.0) << " cm" << endl; // 25.0 mm as 2.5cm cout << " 350 cm as " << convert<centi, kilo>(350.0) << " km" << endl; // 350 cm as 0.0035 km cout << " 2 mile as " << convert<mile, kilo>(2.) << " km" << endl; // 2 mile as 3.21869 km

Time utilities chrono duration : time differences

: time differences time points : absolute time (difference to the epoch)

: absolute time (difference to the epoch) clocks : epoch : zero time of a clock. (e.g. 1.1.1970) 3 predefined clock: system_clock , steady_clock , high_resolution_clock .

: time_point is a template class specific for a clock. duration is a template class specific for representation and a period. typedef duration<integer_type, ratio<60>> minutes; typedef duration<integer_type, milli> milliseconds; // milli as typedef ratio<1, 1000> milli;

chrono Example: // get the current time : chrono::system_clock::time_point now = chrono::system_clock::now(); chrono::system_clock::time_point later = now + chrono::hours(1); // in one hour auto diff1 = later - now; // in chrono::system_clock::duration chrono::minutes diff2 = chrono::duration_cast<chrono::minutes>(later-now); cout << "difference in min: " << diff2.count() << endl; // difference in min : 60 typedef chrono::duration<double, ratio<3600,1>> dhours; auto diff3 = chrono::duration_cast<dhours>(later-chrono::system_clock::now()); cout << "difference in hours: " << diff3.count() << endl; // difference in hours : 0.999999

tuple generalization of std::pair tuple<int, double, string> var(1, 3.14, "Hallo"); int i = get<0>(var); double d = get<1>(var); get<2>(var) = "good bye"; Member access with compile time generated assessors get<N>();

(No iteration over elements at runtime.)

make_tuple & tie make_tuple Prefer the usage of make_tuple as you should prefer make_pair (without explicit template arguments). tuple<int, double, string> foo() { return make_tuple(1, 3.14, "C++"); } tie Assign multiple variables to a tuple (or pair). double d; int i; string s; tie(i, d, s) = foo(); assert(i == 1 && d == 3.14 && s = "C++"); The combination of tuple and tie add multiple result values to C++.

Deprecated STL: auto_ptr (use unique_ptr)

Function object base classes unary_function, binary_function, ptr_fun, mem_fun,... (use function and mem_fn)

bind1st, bind2nd (use bind or lambda instead)

Questions

/