Slides about the fat and the gaunt years of C++ and why the language currently experiences its renaissance. They also explain what Modern C++ is. Finally, you'll learn how the language evolved along with its ecosystem and where will it go further.
Right Money Management App For Your Financial Goals
C++: a fast tour of a fast language
1. C++: A FAST TOUR
OF A FAST LANGUAGE
ADRIAN OSTROWSKI
4DEVELOPERS, SEPTEMBER 25 , 2018TH
2. • spent childhood in crop fields
• 8 years in the software field, 6 years in C++
• west const propagator
• interested in Agile, quality and performance
• lifelong learner
• music lover
• gamer
whoami
2
3. What we will talk about today?
• the fat and the gaunt years of C++
• why the language currently experiences its renaissance
• what is Modern C++ and why you should care
• how the language evolved and where will it go from here
• how the ecosystem evolved along with the language
What we won't talk about?
• (too much) hard stuff
• why C++ is "better" or "worse" than ${OTHER_LANG}
AGENDA
3
7. THE SAME NOW AS WHEN THE LANGUAGE WAS CREATED
1 There should be no language beneath C++ (except assembly)
2 You only pay for what you use
3 Offer high-level abstractions at low cost (strong aim for zero-cost)
PHILOSOPHY OF C++
7
12. SHIFT OF PRIORITIES
• Battery life
• Performance per watt
• Low memory consumption
• Retaining responsiveness
MOBILE PLATFORMS
12
13. SCALE CHANGES EVERYTHING
• Low costs of software compared to total costs
• Performance per watt
• Optimizations scale through servers
CLOUD PLATFORMS
13
15. • performance (game development, high-frequency trading)
• mission-critical systems, e.g. aeroplanes
• OS development
• automotive industry
• blockchain
• building blocks, e.g. for AI and ML
WHERE ELSE IS C++ USED?
15
21. • C++11?
• C++14?
• C++17?
• Whatever the newest standard is?
WHAT IS MODERN C++?
18
22. • C++11?
• C++14?
• C++17?
• Whatever the newest standard is?
NOPE
WHAT IS MODERN C++?
18
23. • C++11?
• C++14?
• C++17?
• Whatever the newest standard is?
NOPE
Modern C++ is not about the standard
WHAT IS MODERN C++?
18
24. • C++11?
• C++14?
• C++17?
• Whatever the newest standard is?
NOPE
Modern C++ is not about the standard
It's a philosophy of code design
WHAT IS MODERN C++?
18
25. • C++11?
• C++14?
• C++17?
• Whatever the newest standard is?
NOPE
Modern C++ is not about the standard
It's a philosophy of code design
C++11 was heavily influenced by industry practices and popular libraries
WHAT IS MODERN C++?
18
27. Modern C++ isn't afraid of:
• RAII
SO HOW IT'S DIFFERENT THAN "OLD-STYLE" C++?
20
28. Modern C++ isn't afraid of:
• RAII
• reuse of (standard) library components
SO HOW IT'S DIFFERENT THAN "OLD-STYLE" C++?
20
29. Modern C++ isn't afraid of:
• RAII
• reuse of (standard) library components
• templates and metaprogramming
SO HOW IT'S DIFFERENT THAN "OLD-STYLE" C++?
20
30. Modern C++ isn't afraid of:
• RAII
• reuse of (standard) library components
• templates and metaprogramming
• mixing programming paradigms
SO HOW IT'S DIFFERENT THAN "OLD-STYLE" C++?
20
31. Have you ever leaked a resource?
RESOURCE ACQUISITION IS INITIALIZATION
21
32. Have you ever leaked a resource?
Have you ever double-freed a resource?
RESOURCE ACQUISITION IS INITIALIZATION
21
33. Have you ever leaked a resource?
Have you ever double-freed a resource?
Had a hard time releasing them if an exception occurs?
RESOURCE ACQUISITION IS INITIALIZATION
21
34. Have you ever leaked a resource?
Have you ever double-freed a resource?
Had a hard time releasing them if an exception occurs?
RAII takes the burden of resource handling from the programmer.
RESOURCE ACQUISITION IS INITIALIZATION
21
38. template<typename T, typename OverflowPolicy>
class Treasury {
public:
void add(T amount) {
if (OverflowPolicy::Check(treasure_, amount)) {
treasure_ += amount;
}
}
bool has_enough_value() {
// TODO: become less greedy
return false;
}
// ...
private:
T treasure_{};
};
POLICY-BASED DESIGN
25
39. template<typename T>
struct RobinHoodPolicy {
bool Check(T& treasure, T amount) {
auto space = std::numeric_limits<T>::max() - treasure_;
if (space < amount) {
Steal(amount - space);
}
return true;
}
};
using NottinghamTreasury = Treasury<int, RobinHoodPolicy<int>>;
POLICY-BASED DESIGN, CONT'D
26
40. Some great and free for commercial use libraries:
• Boost
• Abseil
• EASTL
• BDE/BSL
• Folly
REUSE EXISTING LIBRARIES
27
41. Some great and free for commercial use libraries:
• Boost
• Abseil
• EASTL
• BDE/BSL
• Folly
Other libraries can be pulled by package managers like Conan.
REUSE EXISTING LIBRARIES
27
44. template<int N>
struct Factorial {
static const int value = N * Factorial<N-1>::value;
};
template<>
struct Factorial<0> {
static const int value = 1;
};
int main() {
std::cout << Factorial<12>::value << 'n';
}
MODERN C++: TEMPLATES AND METAPROGRAMMING
30
45. template<int N>
struct Factorial {
static const int value = N * Factorial<N-1>::value;
};
template<>
struct Factorial<0> {
static const int value = 1;
};
int main() {
std::cout << Factorial<12>::value << 'n';
}
C++ shifts more and more to compile-time computations
MODERN C++: TEMPLATES AND METAPROGRAMMING
30
46. constexpr int factorial(int n) {
int result = n;
while (n > 1)
result *= --n;
return result;
}
static_assert(factorial(4) == 24);
int main() {
std::cout << factorial(12) << 'n';
}
CONSTEXPR FUNCTIONS
31
47. constexpr int factorial(int n) {
int result = n;
while (n > 1)
result *= --n;
return result;
}
static_assert(factorial(4) == 24);
int main() {
std::cout << factorial(12) << 'n';
}
Compile-time gets easier with newer standards
CONSTEXPR FUNCTIONS
31
48. Most use C++ as procedural/object-oriented, imperative language
MODERN C++: MIXING PROGRAMMING PARADIGMS
32
49. Most use C++ as procedural/object-oriented, imperative language
It allows more than that.
MODERN C++: MIXING PROGRAMMING PARADIGMS
32
50. • templates
• most of the standard library
• auto keyword
• template metaprogramming
• constexpr functions
GENERIC PROGRAMMING
33
55. • safer and cleaner code
TO SUM UP, MODERN C++ RESULTS IN
36
56. • safer and cleaner code
• which is faster to develop
TO SUM UP, MODERN C++ RESULTS IN
36
57. • safer and cleaner code
• which is faster to develop
• and faster at runtime!
TO SUM UP, MODERN C++ RESULTS IN
36
58. • safer and cleaner code
• which is faster to develop
• and faster at runtime!
And it plays great with recent C++ standards
TO SUM UP, MODERN C++ RESULTS IN
36
61. • Passing ownership between objects using std::move
std::unique_ptr<T> up(new T{});
std::unique_ptr<T> up2 = std::move(up);
foo(std::move(up2));
MOVE SEMANTICS
39
62. • Passing ownership between objects using std::move
std::unique_ptr<T> up(new T{});
std::unique_ptr<T> up2 = std::move(up);
foo(std::move(up2));
• Better performance by avoiding copies
MOVE SEMANTICS
39
63. • Passing ownership between objects using std::move
std::unique_ptr<T> up(new T{});
std::unique_ptr<T> up2 = std::move(up);
foo(std::move(up2));
• Better performance by avoiding copies
• Moving creates an r-value reference, similarly to creating a new object
MOVE SEMANTICS
39
64. • Templates accepting arbitrary number of arguments, e.g. for creating tuples
• Example: make_unique in C++11
template<class T, class... Args>
inline std::unique_ptr<T> make_unique(Args&&... args) {
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
VARIADIC TEMPLATES
40
65. • Lightweight list of values
• Can be used to construct containers in one go
void foo(const std::vector<int> &v);
auto numbers = { 1, 2, 3 }; // std::initializer_list<int>
foo({numbers});
foo({3, 4, 5});
foo({});
std::map<int, std::string> my_map{
{ 1, "one" },
{ 2, "two" }
};
INITIALIZER LISTS
41
66. • Compile-time checks with simple error messages
static_assert(sizeof(void *) * CHAR_BIT == 8, "64-bit platform required");
template <class T>
T calculate(T x, T y) {
static_assert(std::is_arithmetic<T>::value,
"Can't calculate using non-numerical types");
// ...
}
STATIC ASSERTIONS
42
67. • automatic type deduction for variables, return types, etc.
• use it for correctness – avoid accidental type conversions
• use if for generic programming – easier maintenance in case the used type changes
• use it for readability - less is more
• use it for safety – you can’t forget to initialize it
// no changes when get_widget() returns unique_ptr instead of shared_ptr
auto widget = get_widget();
auto it = map.find(42); // auto vs std::map<int, std::string>::iterator;
auto func = [](int x) { return x * 2; };
auto KEYWORD
43
68. • functions are now first class citizens
• excellent for use with standard functions
[](){ std::cout << "Hello Lambda World!n"; };
int x = 1;
auto f1 = [&x] { return x *= 2; }; // modify original x
auto f2 = [x] () mutable { return x *= 2; }; // modify copy
std::vector<int> v{1, -2, 3};
std::sort(begin(v), end(v), [](int a, int b) { return b*b > a*a });
LAMBDA EXPRESSIONS
44
69. std::vector<int> v{1, 2, 3, 4, 5};
for (int i: v) {
std::cout << i << ' ';
}
for (int& i: v) {
i *= 2;
}
RANGE-BASED FOR LOOPS
45
71. using namespace std::chrono;
auto start = steady_clock::now(); // time_point<steady_clock>
// insert measured work here
auto end = steady_clock::now();
auto micros = duration_cast<microseconds>(end-start); // duration<long, std::micro>
std::cout << micros.count() << 'n';
auto blink_of_an_eye = std::chrono::milliseconds(300);
// more convenient since C++14
using namespace std::chrono::literals;
auto day = 24h;
std::chrono
47
77. // before
template<int N>
constexpr int fibonacci() {return fibonacci<N-1>() + fibonacci<N-2>(); }
template<>
constexpr int fibonacci<1>() { return 1; }
template<>
constexpr int fibonacci<0>() { return 0; }
CONSTEXPR IF
53
78. // before
template<int N>
constexpr int fibonacci() {return fibonacci<N-1>() + fibonacci<N-2>(); }
template<>
constexpr int fibonacci<1>() { return 1; }
template<>
constexpr int fibonacci<0>() { return 0; }
// after
template<int N>
constexpr int fibonacci() {
if constexpr (N>=2)
return fibonacci<N-1>() + fibonacci<N-2>();
else
return N;
}
CONSTEXPR IF
53
79. // in some class
std::vector v{1, 2, 3};
std::mutex mut;
// in some function
if (auto lock = std::scoped_lock{mut}; !v.empty()) {
v.pop_back();
}
IFS AND SWITCHES WITH INITIALIZERS
54
80. // in some class
std::vector v{1, 2, 3};
std::mutex mut;
// in some function
if (auto lock = std::scoped_lock{mut}; !v.empty()) {
v.pop_back();
}
switch (Command cmd = read_command(); cmd.type) { /* ... */}
IFS AND SWITCHES WITH INITIALIZERS
54
81. // in some class
std::vector v{1, 2, 3};
std::mutex mut;
// in some function
if (auto lock = std::scoped_lock{mut}; !v.empty()) {
v.pop_back();
}
switch (Command cmd = read_command(); cmd.type) { /* ... */}
if (auto [iter, success] = myset.insert("X"); success) {/* ... */}
IFS AND SWITCHES WITH INITIALIZERS
54
82. auto v = std::variant<int, string>{42};
std::get<int>(v); // returns 42
std::get<0>(v); // returns 42
std::get<double>(v); // compile-time error
v = "not an int";
std::get<int>(v); // throws std::bad_variant_access
STD::VARIANT - A TYPE-SAFE UNION
55
84. What can you tell about the following function?
int* parse_number(const std::string& input);
STD::OPTIONAL FOR CLEAN INTERFACES
57
85. What can you tell about the following function?
int* parse_number(const std::string& input);
How about this one?
int parse_number(const std::string& input);
STD::OPTIONAL FOR CLEAN INTERFACES
57
86. What can you tell about the following function?
int* parse_number(const std::string& input);
How about this one?
int parse_number(const std::string& input);
What about this one?
std::optional<int> parse_number(const std::string& input);
STD::OPTIONAL FOR CLEAN INTERFACES
57
90. Which is faster? Why?
void foo(const std::string& str);
foo("A quick brown fox jumps over the lazy dog");
// vs
void bar(std::string_view);
bar("A quick brown fox jumps over the lazy dog");
STD::STRING_VIEW
60
95. • type-checking in templates
• simpler template error messages
• easier selection of overloads and specializations
• constraining automatic type deduction
template<typename T>
concept Hashable = requires(T a) {
{ std::hash<T>{}(a) } -> std::size_t;
};
template<Hashable Key>
auto get_bucket(Key key, std::size_t max_buckets) -> std::size_t;
CONCEPTS - C++20
64
96. std::list<int> l = {2, 1, 3};
std::sort(l.begin(), l.end());
In instantiation of 'void std::__sort(_RandomAccessIterator, _RandomAccessIterator,
_Compare) [with _RandomAccessIterator = std::_List_iterator<int>; _Compare =
__gnu_cxx::__ops::_Iter_less_iter]':
error: no match for 'operator-' (operand types are 'std::_List_iterator<int>'
and 'std::_List_iterator<int>')
std::__lg(__last - __first) * 2,
// few dozens more lines of error messages
error: cannot call function 'void std::sort(_RAIter, _RAIter)
[with _RAIter = std::_List_iterator<int>]'
note: concept 'RandomAccessIterator()' was not satisfied
CONCEPTS - ERROR MESSAGES
65
97. void foo(const std::vector<int>& v)
[[expects: !v.empty()]]
[[ensures audit v2: is_sorted(v2)]] {
int x = g();
[[assert: x > 0]]
auto v2 = bar(v, x);
return v2;
}
• Possible enforcing levels are: default, audit, and axiom
CONTRACTS - C++20
66
99. generator<int> even_numbers() {
auto current = 0;
while (true) {
co_yield current;
current += 2;
}
}
auto find_line(std::string resource, std::string key)
-> std::future<std::expected<std::string>> {
while (auto line = co_await fetch_line(co_await load(resource))) {
if (contains(line, key))
co_return line;
}
co_return std::unexpected(not_found(resource));
}
COROUTINES - C++20/23
67
100. • Import a module instead of #including <files>
• Much, much faster compile times
• No more splitting code between header and cpp files
• Easier package management
MODULES - C++20/23
68
102. What problems did we have?
• compiles were slow
• compile errors were complicated
• templates were hard to debug
• memory leaks
• no central place to go for news, papers etc.
ECOSYSTEM EVOLUTION - CAUSES
70
107. • Bjarne Stroustrup's photo by Julia Kryuchkova (edited), CC-BY-SA 2.5, Wikipedia
• Bell Labs Holmdel Complex by Lee Beaumont, retouched by MBisanz & Kylu, CC-BY-SA 2.0,
Wikipedia
• Livraria do Senado by Senado Federal, CC-BY 2.0, Wikipedia
• Microsoft Windows 95 screenshot, used with permission from Microsoft
• Working lat(t)e by Kuba Bożanowski, CC-BY 2.0, Flickr
• Alexander Stepanov's photo by Paul R. McJones, CC-BY-SA 3.0, Wikipedia
• IEEE Spectrum Ranking
• Tanks by Roger May, CC-BY-SA 2.0, Geograph.co.uk
ATTRIBUTIONS
75