Slides by Ben / Code samples by Coliru / Layout by reveal.js
Every example that follows compiles with
>> illegal in C++98
int main() { std::vector<std::vector<std::string> > vec; // Now you can write: std::vector<std::vector<std::string>> vec2; }
All about type inference
Syntax: auto variable initializer auto function -> return type
Specifies that the type of the variable that is being declared will be automatically deduced from its initializer.
auto i = 42; auto u = 1729U; auto str = std::string("Mehr Bier");
If you are lazy
struct Beer { Beer(const char* s) : name(s) {} std::string name; }; int main() { std::vector<Beer> vec{ "Thier", "Bergmann", "Kronen" }; for (std::vector<Beer>::iterator it = vec.begin(); it != vec.end(); ++it) { std::cout << it->name << "-Pils\n"; } }
If you want to avoid bugs
char buf[20]; std::istringstream stream("Hello, there!"); stream.read(buf, sizeof buf); // Conversion from std::streamsize to size_t size_t bytes_extracted = stream.gcount(); std::cout << "Characters extracted " << bytes_extracted << '\n';
template<class T, class U> auto add(T t, U u) -> decltype(t + u) { return t + u; }
All about uniform initialization
{ }
#include <iostream> #include <string> #include <vector> #include <unordered_map> int main() { std::vector<double> vec{ 1, 2, 3.456, 99.99 }; std::unordered_map<std::string, std::string> beers{ {"Thier","Dortmund"}, {"Krombacher","Kreuztal"}, {"Fiege","Bochum"} }; for (const auto& beer : beers) std::cout << beer.first << ", " << beer.second << std::endl; }
Supported since November 2012 CTP
#include <initializer_list> template<class T> class ListJ { public: // initializer-list constructor ListJ (std::initializer_list<T> s) { // get the right amount of space reserve(s.size()); // initialize elements uninitialized_copy(s.begin(), s.end(), elem); // set size sz = s.size(); } // ... };
Iterate through a range
which is anything with a begin() and end()
or with a begin() and length
int main() { std::vector<std::string> vec{"Bergmann", "Union Export", "Fiege"}; for (auto& beer : vec) // access as reference to change a value { std::for_each(begin(beer), end(beer), [](char& c) { c = std::toupper(c); }); } // access as const-ref to avoid copying for (const auto& beer : vec) std::cout << beer << '\n'; for (auto x : { 11,22,33,44,55,66,77 }) std::cout << x << '\n'; }
An anonymous function (a function without a name, thats all)
Can have an optional capture clause (that makes it a closure)
Syntax: [capture-list] (params) {body} [capture-list] {body} [capture-list] (params) -> ret {body} [capture-list] (params) mutable {body}
int main() { std::vector<int> vec{ 1,2,3,4,5,6,7 }; int x = 4; vec.erase(std::remove_if(vec.begin(), vec.end(), [x](int n) { return n < x; } ), vec.end()); std::cout << "vec: "; for (auto i: vec) { std::cout << i << ' '; } std::cout << '\n'; // The type of a closure cannot be named, but can // be inferred with auto auto add4 = [](int i) { return i+4; }; std::cout << "add4: " << add4(6) << '\n'; }
Access variables from outer scope (and optionally modify them)
#include <vector> #include <iostream> #include <string> int main() { std::vector<std::string> vec{ "Dortmunder Actien-Brauerei" }; auto push_to_vec = [](const std::string& beer) { vec.push_back(beer); }; for (const auto& b : { "Hansa", "Bergmann", "Thier" }) { push_to_vec(b); } for (const auto& b : vec) std::cout << b << '\n'; }
capture-list: [a,&b] a is captured by value, b is captured by ref [this] captures this pointer by value [&] captures all variables used in body of lambda by ref [=] captures all variables used in body of lambda by value [] captures nothing
Now on to the quest on getting rid of owning raw-pointers: Smart pointers!
new, delete new[], delete[]
#include <memory> struct Foo { Foo() { std::cout << "Foo::Foo\n"; } }; int main() { std::unique_ptr<Foo> p1(new Foo); // p1 owns Foo // Foo instance is destroyed when p1 goes out of scope }
#include <memory> int main() { { std::shared_ptr<int> p1(new int); // count is 1 { std::shared_ptr<int> p2(p1); // count is 2 { std::shared_ptr<int> p3(p1); // count is 3 } // count goes back down to 2 } // count goes back down to 1 } // here the count goes to 0 and the int is deleted. }
Hash tables, yeah :/
#include <unordered_map>
template< class Key, class T, class Hash = std::hash<Key>, class KeyEqual = std::equal_to<Key>, class Allocator = std::allocator< std::pair<const Key, T> > > class unordered_map;
Control of defaults
Remember?
class Foo { public: // ... private: // Never defined Foo(const Foo&); Foo& operator=(const Foo&); };
Now you can just write:
class Foo { public: Foo(const Foo&) = delete; Foo& operator=(const Foo&) = delete; // ... };
We can delete an undesired conversion like this:
struct Foo { // ... Foo(long long); // can initialize with an long long Foo(long) = delete; // but not anything less! };
const char* str = R"("quoted string")"; // the string is "quoted string"
Very useful if you have inline SQL or regexp.
Motivating example:
#include <iostream> #include <regex> int main() { const char* pat = R"((\+|-)?[[:digit:]]+)"; std::regex integer_pattern(pat); const char* input = "-123"; std::cout << (std::regex_match(input, integer_pattern) ? "matches" : "does not match") << std::endl; }
A null pointer literal
Yes, it has a type: std::nullptr_t
Contrary:
#define NULL 0
Actually, implementation defined, but pretty likely
void f(int* pi) { } void f(double* pd) { } void f(std::nullptr_t nullp) { } int main() { int* pi; double* pd; f(pi); f(pd); f(nullptr); // would be ambiguous without void f(nullptr_t) // f(NULL); // ambiguous overload }
Pretty easy to transform your code base, too ;)
$ sed -i `s/NULL/nullptr/g` *.{h,cpp}