Features of

modern C++

Johan Burell

What makes C++ hard?

Challenges

  • Complexity
  • Memory management
  • Legacy (primarily from C)
  • Multi paradigm
  • (Compilation)

Strengths

  • Flexibility
  • Performance
  • Widespread usage
  • Multiparadigm
  • Type safe (if done right...)

A "new" language

Within C++,there is a much smaller and cleaner language struggling to get out.

- Bjarne Stroustrup

...and no, that smaller and cleaner language is not Java or C#.

- Bjarne Stroustrup

You can write C++ programs that are statically type safe and have no resource leaks. You can do that without loss of performance and without limiting C++’s expressive power. This supports the general thesis that garbage collection is neither necessary nor sufficient for quality software. Our core C++ guidelines makes such code simpler to write than older styles of C++ and the safety can be validated by tools that should soon be available as open source.

 

- Bjarne Stroustrup

The state of C++ today

Timeline

C++11

(aka C++0x)

auto, lambdas, thread model, initializer lists, typed enums, smart pointers... etc

C++14

(aka C++1y)

auto return type, variable templates, generic lambdas and capture expressions... etc

C++17

(aka C++1z)

File system, Parallellism, various library fixes... "TBD"

New language features!

Const expression / foreach-loops

Subtitle

#include <iostream>
using namespace std;
constexpr int numElements() { return 3; }

int myArr[numElements() + 2];

int main() {
    for(int &a: myArr) {
        a = 2;
    }

    cout << myArr[3] << endl;
    return 0;
}

Move semantics / initializer-lists

Subtitle

struct MyStruct {
    int a;
    float b;
};

MyStruct modify(MyStruct myStruct) {
    myStruct.a = 5;
    return myStruct;
}

int main () {
    MyStruct myStruct{2, 1.2};
    myStruct = modify(myStruct);
    return 0;
}

Smart pointers

Subtitle

#include <memory>
using namespace std;

struct MyObject {
    int value;
};

void aTypicalFunc(unique_ptr<MyObject>& smartObj, MyObject* dumbObj) {
    smartObj->value = 5; dumbObj->value = 3;
}

int main() {
    unique_ptr<MyObject> myObj = make_unique<MyObject>();
    MyObject* myLeakingObject = new MyObject();
    //unique_ptr<MyObject> myObj2 = myObj;     // Compile err
    unique_ptr<MyObject> myObj3 = move(myObj); // Valid
    aTypicalFunc(myObj3, myLeakingObject);

    shared_ptr<int> p1(new int(5));
    shared_ptr<int> p2 = p1;              //Both now own the memory.
    p1.reset();                           //Memory still exists, due to p2.
    p2.reset();                           //Deletes the memory, no owners left
    return 0;
}

Auto / decltype

Subtitle

struct SomeStruct {
    SomeStruct(auto x, auto y) : someVal{x}, someOtherVal{y} {}
    int someVal;
private:
    double someOtherVal;
};

void changeObj (auto& myObj) {
    myObj.someVal = 7;
}

int main() {
    SomeStruct myStruct{3, 3.14};
    changeObj(myStruct);
    decltype(myStruct) someOtherStruct{5, 1.2};
    return 0;
}

Lambdas and more decltype

Subtitle

template<class Lhs, class Rhs>
auto addFunc(const Lhs &lhs, const Rhs &rhs) 
    -> decltype(lhs+rhs) 
{ return lhs + rhs; }

auto mulFunc = [](auto a, auto b){ return a * b; };

int main() {
    auto myVal = 2;
    auto myVal2 = 3;
    auto result = addFunc(myVal, myVal2) - mulFunc(myVal, myVal2);

    auto closure = [&](){ myVal = myVal2; };
    closure();

    return 0;
}

Threads / Futures / Promises

Subtitle

#include <iostream>       // std::cout
#include <functional>     // std::ref
#include <thread>         // std::thread
#include <future>         // std::promise, std::future
using namespace std;

void print_int(future<int>& fut) {
  int x = fut.get();
  cout << "value: " << x << '\n';
}

int main ()
{
  promise<int> prom;                     // create promise
  future<int> fut = prom.get_future();   // engagement with future
  thread th1(print_int, ref(fut));       // send future to new thread

  prom.set_value(10);                    // fulfill promise
                                         // (synchronizes with getting the future)
  th1.join();
  return 0;
}

Override

Subtitle

struct Base {
    virtual float some_func(float) = 0;
    virtual float some_other_func() final { return 3.9; };
};

struct Derived : Base {
    float some_func(float a) override {
        return a * 2;
    }
};

int main() {
    auto d = Derived();
    auto e = d.some_func(d.some_other_func());
    return 0;
}

GSL

(Guidelines Support Library)

Span (slices)

Subtitle

#include "gsl.h"
using namespace gsl;

int doStuff(span<int> stuff) {
    int sum = 0;
    for(int& a: stuff) {
        sum += a;
    }
    return sum;
}

int main() {
    int stuff[] = {1,2,3,4,5};
    int sum = doStuff(as_span(stuff).subspan(1, 3));

    return 0;
}

Owner

Subtitle

#include "gsl.h"
#include<iostream>
using namespace std;
using namespace gsl;

void doStuff(owner<int*> data, not_null<string*> str) {
    cout << *str << endl;
}

int main() {
    int* data = new int[5];
    //string* str = nullptr;           // Error
    string* str = new string("Hej");
    doStuff(data, str);

    return 0;
}

Further reading

(Cling)

Questions?

Thanks for listening!

Made with Slides.com