C++ 11

A Language Renaissance

Kevin Ottens

conf.kde.in 2014

C++98

C++03

C++11

C++11 feels like a new language

Bjarne Stroustrup

Good compiler support

Except for Visual Studio which is a bit late...

New Idioms

New STL Tools

Even more to come

C++14 & C++17

Let's start!

Convenience

auto

Before

int val = 42;
const int cval = 42;
Contact *c = new Contact;

std::vector<int> values = ...;
for (std::vector<int>::const_iterator it = values.cbegin(), end = values.cend();
     it != end; it++) {
    int val = *it;
    std::cout << val << endl;
}

After

auto val = 42;
const auto cval = 42;
auto c = new Contact;

std::vector<int> values = ...;
for (auto it = values.cbegin(), end = values.cend();
     it != values.cend(); it++) {
    auto val = *it;
    std::cout << val << endl;
}

Range for

Before

std::vector<int> values = ...;
for (std::vector<int>::const_iterator it = values.cbegin(), end = values.cend();
     it != end; it++) {
    int val = *it;
    std::cout << val << endl;
}

After auto

std::vector<int> values = ...;
for (auto it = values.cbegin(), end = values.cend();
     it != end; it++) {
    auto val = *it;
    std::cout << val << endl;
}

After

std::vector<int> values = ...;
for (auto val : values) {
    std::cout << val << endl;
}

After (bis)

std::vector<int> values = ...;
for (auto &val : values) {
    val = val * val;
}

Inherited constructors

Before

class Parent
{
public:
    Parent(int i) : value(i) { /* do something */ }
protected:
    int value;
};

class Child : public Parent
{
public:
    Child(int i) : Parent(i), flag(false) {}
protected:
    bool flag;
};

After

class Parent
{
public:
    Parent(int i) : value(i) { /* do something */ }
protected:
    int value;
};

class Child : public Parent
{
public:
    using Parent::Parent;
protected:
    bool flag = false;
};

Delegated Constructors

Before

class MyClass
{
public:
    MyClass(int i, int j) { init(i, j); }
    MyClass(int i, const char *j) { init(i, atoi(j)); }
private:
    void init(int i, int j) { /* do something */ }
};

After

class MyClass
{
public:
    MyClass(int i, int j) { /* do something */ }
    MyClass(int i, const char *j) : MyClass(i, atoi(j)) {}
};

Uniform Initialization

Before

float array[] = { 0.0f, 1.42f, 42.3f };

int value = 7;
int other(8);

Circle c(Point(0, 0), 12);

std::vector<int> values;
values.push_back(1);
values.push_back(2);

After

float array[] = { 0.0f, 1.42f, 42.3f };

int value = {7};
int other{8};

Circle c1{ Point{0, 0}, 12 };
Circle c2{ {0, 0}, 12 };

std::vector<int> values{ 1, 2 };

Initializer Lists

#include <initializer_list>

class SharedMemList
{
public:
    SharedMemList(std::initializer_list<int> l)
    {
        for (int param : l) {
            storeInSharedMem(param);
        }
    }
...
};

Type Safety

nullptr

Before

void f(int value);
void f(void *data);
...

f(0); // int
f(0L); // ambiguous...
f(NULL); // ambiguous...

After

void f(int value);
void f(void *data);
...

f(0); // int
f(nullptr); // void*

override

class Parent
{
public:
    virtual void method();
};

class Child : public Parent
{
public:
    void method() override;
};
class Parent
{
public:
    virtual void method(int value);
};

class Child : public Parent
{
public:
    void method() override; // error!
};

final

class Parent
{
public:
    virtual void method() final;
};

class Child : public Parent
{
public:
    void method(); // error!
};
class Parent final
{
public:
    virtual void method();
};

class Child : public Parent // error!
{
};

Smart Pointers

std::shared_ptr

using namespace std;

shared_ptr<Contact> c{new Contact(name, address)};
auto c = make_shared<Contact>(name, address);

// We assume `class Employee : public Contact`

// Ouch!
shared_ptr<Employee> e{ dynamic_cast<Employee>(c.get()) };

// Better!
auto e = dynamic_pointer_cast<Employee>(c);

std::weak_ptr

using namespace std;

shared_ptr<Contact> shared_c
    = make_shared<Contact>(name, address);

// No refcount
weak_ptr<Contact> weak_c = shared_c;

// Refcount
shared_ptr<Contact> shared_c2 = weak_c.lock();

std::unique_ptr

class Contact
{
    ...
private:
    std::unique_ptr<RecordHandle> m_dbHandle;
};

void writeConfig()
{
    std::unique_ptr<FileHandle> file;
    ...
    if (error) return;
    ...
}

Functional

λ Functions

auto surface = [](int w, int h) { return w * h; };
int s = surface(4, 5);

std::vector<int> v{ 1, 2, 3, 4, 5 };
std::transform(v.begin(), v.end(),
               v.begin(),
               [](int v) { return v * v; });

// For Qt 5 users
connect(lineEdit, &QLineEdit::textChanged,
        [](const QString &text) { qDebug() << text; });
std::vector<int> in{ 2, 3, 4, 6, 9 };
std::vector<int> out(3);
int x = 2;

auto multipleOfX = [x](int y) { return y % x == 0; };
x = 3;
std::copy_if(in.begin(), in.end(),
             out.begin(), multipleOfX);
// out contains 2, 4 and 6
std::vector<int> in{ 2, 3, 4, 6, 9 };
std::vector<int> out(3);
int x = 2;

auto multipleOfX = [&x](int y) { return y % x == 0; }
x = 3;
std::copy_if(in.begin(), in.end(),
             out.begin(), multipleOfX);
// out contains 3, 6 and 9
QList<QAction*> widthActions = ...;
PaintArea *area = ...;

for (QAction *action : widthActions) {
    const int width = action->property("width").toInt();
    connect(action, &QAction::triggered,
            [width, area]() {
                area->setPenWidth(width);
            }
           );
}

std::function

using namespace std;

float binder(float x, function<float(float, float)> f)
{
    return f(x, x);
}

void register(const char *type,
              function<Widget*(int)> factory);

std::mem_fn

auto widgetIsHidden = std::mem_fn(&Widget::isHidden);

Widget *w = ...;
if (widgetIsHidden(w)) { ... }

std::vector<Widget*> widgets = ...;
std::cout << "Hidden widgets: "
          << std::count_if(widgets.cbegin(),
                           widgets.cend(),
                           widgetIsHidden);

std::bind

float square(float a) { return a * a; }
float sum(float a, float b) { return a + b; }

auto square42 = std::bind(square, 42);
std::cout << square42() << std::endl; // 1764

auto sum41 = std::bind(sum, 41, std::placeholders::_1);
std::cout << sum41(1) << std::endl; // 42
bool less_than(int a, int b)
{
    return x < y;
}

std::vector<int> in{ 1, 2, 4, 8, 16 };
std::vector<int> out(3);

using namespace std::placeholders;
std::copy_if(in.begin(), in.end(),
             out.begin(), std::bind(less_than, _1, 8));
// out contains 1, 2 and 4

DSL

User-Defined Literals

struct Weight {
    explicit Weight(double kg) : kilograms(kg) {}
    double kilograms;
};

constexpr Weight operator "" _kg(double kg) {
    return Weight{kg};
}

constexpr Weight operator "" _lb(double lb) {
    return Weight{lb * 0.45359237};
}

// Assume operator + exists for Weight
auto weight = 2.0_kg + 3.0_lb;
// Assuming types Length and Area

constexpr Length operator "" _m(double m) {
    return Length{m};
}

constexpr Length operator "" _cm(double cm) {
    return Length{cm/100.0};
}

constexpr Area operator "" _sqm(double sqm) {
    return Area{sqm};
}

...
// Assuming proper operators *, + and ==
// for Length and Area

auto area = 10.0_sqm + (2.0_m * 120.0_cm);
if (area == 12.5_sqm) {
    ...
}

Variadic Templates

int maximum(int n)
{
    return n;
}

template<typename... Args>
int maximum(int n, Args... args)
{
    return std::max(n, maximum(args...));
}

auto m = maximum(25, 42, 10, 30);
// m == 42
template<typename ... Types> class Tuple;
template<> class Tuple<> {};

template<typename Head, typename ... Tail>
class Tuple<Head, Tail...> {
    Head m_head;
    Tuple<Tail...> m_tail;

public:
    Tuple(const Head &head, const Tail & ... tail)
        : m_head(head), m_tail(tail...) {}

    Head head() const { return m_head; }
    Tuple<Tail...> tail() const { return m_tail; }
};

Multithread

std::thread

// Puts the result in some shared state
void computeFibonacci(int n);

std::thread t1{computeFibonacci, 42};
std::thread t2{
    []() { std::cout << 42 << endl; }
};

t1.join();
t2.join();

std::mutex

(and friends)

The usual locks...

std::future

+

std::async

unsigned long long fibonacci(unsigned n);

...

std::vector<std::future<unsigned long long>> results;
for (int n = 0; n < 45; n++) {
    results.push_back(
        std::async(launch::async, fibonacci, n)
    );
}

for (auto &result : results) {
    std::cout << result.get() << std::endl;
}

धन्यवाद !