Author: Lao Jiu – technology big millet
B station video: C++ 20 standard -C++ walk 40 years
Socializing: Zhihu
Public account: Lao Jiu School (Surprise for newcomers)
Special statement: the original is not easy, without authorization shall not be reproduced or copied, if you need to reproduce can contact the author authorized
preface
CppCon 2019: Bjarne Stroustrup ‘C++20: C++ at 40’
Bjarne Stroustup, the father of C++, summed up the 40 years that C++ has gone through, starting with the use of “C with Classes” in 1979 and ending in 2019. The end result: a stable version of the C++ 20 standard for the majority of C++ developers.
C++ history
We take wikipedia as the standard to illustrate the development history of C++, we will not refer to the above content, please baidu translation understanding. Our focus today is not on the history of C++, but on a video by Bjarne Stroustup, the father of C++, on the 40 years of C++ development.
The following illustration is accompanied by our explanation, hoping to help you quickly understand the father of C++ on the C++ language and its development process of the description, so as to be able to learn C++ this most awesome, the most powerful programming language. The video we recorded has been uploaded to station B, so that you can watch the corresponding video.
As the department of planning programmer I, all the following reference translation and interpretation, please do not regard as a standard to understand. Read it like a game commentary or a joke or something (because I’m a C++ fan~, all unavoidably will be interpreted with subjective emotions and views), please read this article with a relaxed and happy mood to read it. If there is any deficiency, please correct and supplement.
C++ 20 version features
The father of C++ summed up the features of C++ 20 in two words
- Stability — stability is all that matters.
- Evolution — Update (Keep pace with The Times, go to the top of the trend)
Note: Comparing pictures of Bjarne Stroustrup in his younger days at Bell LABS and now, I can see that the old Bjarne is on the verge of becoming a genius. I think he is very handsome.
Does he look like it now
Heiharchi, the hero of Tekken
Anyway how I look at it, he is now like the existence of the big Boss ah ~ point a thumbs-up!
Development history of C++
From 1977 to 2019
C++ has been used in the development of the first landline phone since 1979, and has been used in the development of our smartphones since then. The application of C++ in the hardware layer has never stopped.
The diagram above shows that the hardware interface used in the phone product in the past and the wireless interface in the smartphone product in the present are both internally called by the third application using software drivers written in C++.
Early 1980s
Ken and Dennis, the fathers of C, simply offered a product that could do almost everything without relying on assembly, a semi-portable system programming language called C. It is semi-portable for two reasons:
- C has no functional prototypes
- Lint simply represents the state of a static program parser
Note: Lint has the following concepts
Lint is simply a programming language lexical and parser.
Most computer applications have less than 1MB of free memory and run at less than 1MHz, so here’s what’s high-tech in this era:
- Having a PDP-11 16 – bit minicomputer is a real challenge
- Have a VT100 terminal, that is to have a kind of art
- A “personal computer” costs around $3,000 (up from $3,000 a few decades ago).
- The IBM PC has only one concept machine
This is a time when “everyone” thinks “object-oriented thinking” is useless, for a simple reason:
- OO things run too slow
- The use field is too few and the requirements are very special
- For most people, it’s just too hard to understand
Enter the year 2019
Here we discuss the C++20 release features:
- New is not the same as old, and new is not the same as bad is not the same as old
- This article is aimed at C++ 98, C++ 14, C++ 20, etc
- I will occasionally brief you on the history of C++
This article does not cover “details” for one reason: each technical point will be covered in an hour during the week.
Suggested learning methodology
Developer attitude towards C++
- Focus on the essence of C++.
- Use C++ “advanced features” only when needed
The attitude of C++ teaching staff is
- Focus on the essence of C++
- Don’t hide key C++ features just because you don’t have space
- Tell people three truths
- There is only one truth
- But the truth doesn’t always come out
- Keep adding details
What is legal and valid
You need good tools to support it, such as the C++ core wizard
C++ principle and trade-off
- C++ is a programming language that allows business definition, functionality implementation, and lightweight abstraction
- Programming language design is more than just a product to be developed
- The logic of continuity is the essence
- Steady pressure to everything
- Things C++ can do for code:
- The world is more complex than we can imagine
- The world is chaotic
- Most applications require steady pressure to everything
- In general, C++ is “do one thing”
- Support the “use as you like” feature
- Not forcing developers to adhere to “purely theoretical things” (like object-oriented programming ideas)
- It will not require only “expert” level developers to use it
- Simplify programming principles (simplify complex things, don’t make simple things complicated)
Higher order goals for C++
The high-level goal of C++ is to follow the aka principle:
- The evolution of
- Stable (backward compatibility, C++ 20 version compiler can compile and run C++ 98 version of the source program)
- Support code upgrade
- Simplicity is at the heart of everything
- Don’t make things complicated
- Don’t make complicated things hard to understand
- Zero cost principle
- What we don’t use, we don’t care about (aka “Don’t divergent principle”)
- Don’t we need to write everything by hand
- Higher-order goals
- The core functions are designed by ourselves and implemented by software
- We developers think about the business functionality itself
Supplement:aka principles
Here I will not refer to the translation, please baidu reference to understand. Since there are many articles of this kind, we will not elaborate on them here.
We change the world
For applications, the value of a programming language is to achieve the quality of the application.
Software is changing the world in two ways:
- Programming and Design
- Abstract: Express your thoughts directly
- Use better hardware
- Code analysis and compile build operations
- Application field
- Application areas of scalability and complexity
- Engineers, scientists, etc
- .
From 1979 to 2019, C++ has been widely used in a variety of fields.
Key features of C++
- The static typing system supports both built-in and user-defined types
- Value and reference semantics are supported
- Use machine resources and operating system resources directly
- System and general resource management
- Support for hybrid software development patterns
- Support for object-oriented programming
- Support for compile-time programming
- Support built-in concurrency through libraries
Supplement:
I do not refer to the translation here, everyone baidu understand. There’s a lot of blotchy stuff on the web, but I’ll just briefly describe it: compile time is the time that application code is converted to machine code (such as binary code), and it usually occurs before runtime.
A static system
The static type system is the foundation of all C++ functionality and supports the following core functions:
- Compile-time error detection
- For example, list LST; . The sort (list); // Error: linked list cannot be accessed randomly
- Runtime error handling can result in higher running costs and complexity
- Execution efficiency
- It’s a direct statement of what we’re thinking, simple and efficient
- Move internal calculations forward from run time to compile time
- Flexibility is achieved through a compilation mechanism solution
- Solve computational overload problems, such as SQRT (2)
- Generic programming such as Vector V; . auto p = find(v,42);
- Support for meta (bit) programming (very popular in modern programming languages)
- Compile-time diagnostics, such as static assertions for static_assert (weekday(August/3/2019) == Sunday)
Note: Because C++ uses compile time for type detection, overload handling, static assertions, and so on, it must take a long time to compile. So when we started writing games in C++ 11, because of the modular design, C++ programming directly using Java and C# coding ideas (everything was written, compiled, and debugged using a C++ project), and after 30,000 lines of code, the compilation was as simple as an old dog!
Value and reference semantic differences
We need two concepts to describe the constitution of things.
The semantics of a value can be assigned to any data type, as follows:
x = y + z; // The variable type can be int built-in, or complex
, or matrix, or other...
x = y; //x is a copy of y; But x and y are independent things. It's like the idea of being and being in a fantasy novel.
Copy the code
Pointer/reference semantics can be assigned to any type as follows:
*p = x; // the value of x can be T*, shared_ptr
, or other...
p = q; //p and q refer to the same thing.
Copy the code
- Handle — Handle (memory address allocated by the operating system)
- Value – Value (something that is stored in memory)
Value types
- Most types are values, such as integers, characters, strings, container types, and so on
- Abstract semantics (usually regular expressions)
- Allocate memory space by stack
- Inline extension
- It is generally implemented using Pointers
Note: The concept of inlining is shown below
I will not refer to the translation here, about the concept of inline, a lot of online bragging, please baidu reference.
Pointer/reference type
- All pointer and reference types can “point” to a thing, such as T*, T&, unQIue_ptr, Forward_Iterator
- One of the core goals of using Pointers/references is to efficiently transfer information data, such as
- auto p = find(lst,”something interesting”);
- sort(v);
- The second core goal of using Pointers/references is to build something non-decentralized (data structures)
- Pointers/references both use machine resources, thus achieving optimal efficiency
About the generic
The essence of generic programming is regularity, both for C++ built-in data types and for user-defined types. See the following example code:
template<Element T> class Vector{
public:
Vector(initializer_list<T>);
/ /...
T* elem; //T* refers to any valid data type in C++, including custom data types
}
// Parameterize the Element type as follows:
Vector<int> vi = {1.2.3}; //C++ built-in data types
Vector<complex<double>> vc = {{1.2}, {3.4}, {5.6}}; // User-defined data type
Vector<Vector<int>> vvi = {{1.2.3}, {4.5.6}, {7.8.9}}; // Nested types
Copy the code
Use machine resources directly
- The main operation is to map the machine instruction set:
- Algorithm: +, -, *, /, %
- Access operations: ->, [], (),…
- A logic operation: &, |, ^ (exclusive or), ~ (complement), > > and < < (displacement), rotate
- Memory is a set of serialized things, such as Pointers to machine addresses as shown in the figure above
- Objects can be composed by simple concatenation, as shown in the figure above
- An array of
- Class/structure
- Note: Handle also has a value of its own
- Simple abstractions of hardware
A set of
- Operates on bits of any size
- &, | ^ &, | ^ (exclusive or), ~ (complement), > > and < < (displacement), rotate
span
-
Operate on a sequence of objects, such as
-
Array <byte, 1024> a;
/ /…
span s{a}; // The size of the declared element type is not displayed
for(const auto x : s) f(x); // No scope error detection
for(auto& x: s) x = 99;
span s2{a, 512}; // Specify a span of one size
span s3{a}; // Specify the span of the element type
-
Laws of onion
- Abstraction layer
- We abstract results like an onion, and the more we peel them away, the more we cry
- Average complexity management
The great god means: Everything has two sides. The more we play with the concept of object-oriented encapsulation, the more complexity is bound to increase. If you don’t play with object-oriented programming, the more code you have, the more complexity you get.
Structure/destructor pairs
Its object resource management architecture: see the Gadget class below
- All object resources must be returned to the operating system after we use them
- Users do not need to know which tool resource is being used
class Gadget{
Gadget(/ * * /); // Initialize/construct the object
// Get memory resources from the operating system
~Gadget(a);// Clear resources
/ /... Copy and move...
/ /... Resetting the user interface...
private:
/ /... Present...
}
Copy the code
System general resource Management
-
Each object has a separate resource, which is represented by
- Need to clean up (destructor)
- You cannot use built-in type Pointers to manage this relationship
-
To calibrate the resource scope, see the sample code below
void f(int n, int x) { Gadget g{n}; // We third-party developers do not need to know how memory resources are managed by the operating system / /... if(x < 100) throw run_time_erro{"Weird!"}; // No memory leaks if(x < 200) return; // No memory leaks / /... } Copy the code
Note: in C++ programming, we often see return written so as not to leak memory.
- There are four ways to control the complex life cycle of an object: create, copy, move, and destruct. See the following example
Gadget f(int n, int x)
{
Gadget g{n}; // Object G can be large
// Object G may contain objects that cannot be copied
/ /...
return g; // There is no memory leak because there is no complexity
// No pointer
// No display declaring memory management
}
auto gg = f(1.2); // Move the Gadget object outside f to save another variable gg
Copy the code
As you can see from the diagram, objects G and GG are two objects, but their contents are the same and their memory is stored in the same location.
General resource Management
- Implementation of implicit memory resource release and security
- All C++ standard library containers manage their elements, including the following
- vector
- List, forward_list(one-way linked list)
- Unordered_map (hash table)
- The set of multiset
- string, path
- Many C++ standard library classes manage non-memory resources, including the following
- thread, jthred, shared_mutex, scoped_lock
- istream, fstream
- unique_ptr, shared_ptr
- Containers can contain non-memory resources, such as recursive operations, vector
>
The module
Modules are one of the hottest concepts in modern programming languages and are used everywhere in JavaScript, including in the Qt framework language, which proves how powerful modular design and development can be. Here is an example of standard C++ module syntax use:
export module map_printer; // Define a module
import std; // Import modules, the order of import does not matter
import my_containers;
export
template<forward_range S>
requires Printable<KeyType<S>>&& Printable<Value_type<S>>
void print_map(const S& m){
for(const auto& [key,val]: m) // Split into keys and values
cout << key << "- >" << val << '\n';
}
Copy the code
-
Modules in C++ have the following main functions:
-
Minimize dependencies between objects
-
Avoid circular dependencies
-
Implementing modular programming
import A;
import B;
It does the same thing as below
import B;
import A
-
Use only the code in the import module, making it possible to resize the code
-
The code in the module is only “copied” once, and only parsed once
-
The assembly
C++ supports the following assembly methods:
- The module
- class
- concept
- The template
- function
- The alias
Generic programming
With these assembly strategies available, let’s take a look at generic programming in the current version of C++20
- Direct use of types to reflect abstract business logic requirements, such as direct mapping of one-way linked lists, integer types, and so on
- Define the business logic requirement as a conceptual type, as shown in the sample code below
template<typename R>
concept Sortable_range =
random_access_range<R> / / a begin ()/end (), + +, [],...
&& permutable<iterator_t<R>> / / a swap (), etc
&& indirect_strict_weak_order<R>; / / such as <
Copy the code
use
void sort(Sortable_range auto&);
sort(vec); //OK: save as a sequential sequence
sort(lst); // Error: Trying to save a linked list as sequential
Copy the code
-
Choose according to abstract requirements
void sort(Sortable_rang auto& container); // The container must be sortable template<typename R> concept Forward_sortable_range = forward_range<R> && sortable<iterator_t<R>> void sort(Forward_sortable_range auto& seq); // Random access is not required sort(vec); //OK: sort by Sortable_range sort(lst); //Ok: Forward_sortable_range is used Copy the code
-
We can’t say
- “Forward_sortable_range is less strict than Sortable_rangeg”
- Let’s do it by definition
- Generic programming (GP) “is a way of programming”, which includes the following
- Define an interface using a concept
- Type specification and interface plus one layer
- In principle, sort(v) and SQRT (x) are a little different
- “Similar to normal programming, but exactly the same.”
- By default, the sort function uses < comparison to sort, although we can specify a different sort, as shown in the example below
template<random_access_range R, class Cmp = less>
require sortable_range<R,Cmp>
constexpr void sort(R&& r, Cmp cmp = {});
sort(v,[](const auto& x, const auto& y){returnx > y; });sort(vs,[](const auto& x, const auto& y){return lower_case_less(x,y); });Copy the code
Object-oriented programming
I will not refer to the translation of this PPT, everyone can understand. Let’s just make one important point: Object-oriented ideas are currently only implemented at runtime.
The point of this slide is that if we don’t implement object-oriented programming ideas at runtime, the only solution for now is static storage.
The C++20 version no longer loads the overloaded() function in time. The current version of C++ is extensible
- Build according to the needs of our third-party developers
- Or build it using existing standards
template<class... Ts>
struct overloaded:Ts... {// Collect N types
using Ts::operator(a).; // Call all types once
};
// Derive the template parameter types
template<class... Ts> overloaded(Ts...)->overloaded<Ts... >Copy the code
Use operating system resources directly
- Simplified memory locking
mutex m1;
int sh1; // Share data
mutex m2;
int sh2; // Another shared data
void obvious(a)
{
/ /...
scoped_lock lck1{m1,m2}; // Get two locks
// Operate shared data
sh1 += sh2;
}// Release two locks
Copy the code
- Double lock initialization operation
mutex mx; // The OS supports synchronous operation and the code cost is high
automic<bool> initx; // Use the relatively convenient atomic variables
int x; // Share data
if(! initx){ lock_guard lck {mx};if(! initx) x =42;
initx = true;
}
/ /... Using the x variable...
Copy the code
- No data competition
Synchronized code is always written in a low-level manner
mutex mx;
automic<bool> initx;
int x;
if(! initx.load(memory_order_acquire)){
mx.lock(a);if(! initx.load(memory_order_relaxed)){
x = 42;
initx.store(true, memory_order_release);
}
mx.unlock(a); }/ /... Using the x variable...
Copy the code
- In principle, do not abstract this low-level code
Let me take a look at the implementation of thread synchronization code prior to C++20
// example for thread::join
#include <iostream> // std::cout
#include <thread> // std::thread, std::this_thread::sleep_for
#include <chrono> // std::chrono::seconds
void pause_thread(int n)
{
std::this_thread::sleep_for (std::chrono::seconds(n));
std::cout << "pause of " << n << " seconds ended\n";
}
int main(a)
{
std::cout << "Spawning 3 threads... \n";
std::thread t1 (pause_thread,1);
std::thread t2 (pause_thread,2);
std::thread t3 (pause_thread,3);
std::cout << "Done spawning threads. Now waiting for them to join:\n";
t1.join(a); t2.join(a); t3.join(a); std::cout <<"All threads joined! \n";
return 0;
}
Copy the code
It used to take more than 20 lines to synchronize correctly, but now it only takes two or three lines.
Concurrent algorithms
Don’t synchronize threads when you don’t have to, and let them do whatever they want.
The C++20 version may not provide concurrent version sorting functionality in a timely manner.
Compile time calculation
The C++20 version moves past run-time computation to compile-time computation for the following reasons:
- Based on execution efficiency and code elegance
- Just do it once, not millions of times
- The runtime error handle is no longer needed
- Constants no longer have data race problems
This can be used at compile time to solve the following problems:
- Overloading and virtual functions
- The template
- Variable template
- Constant expression functions and user-defined types
Constant arguments are called at compile time.
Notice how the following statements are written
cout << weekday{June/21/2016} < <'\n';
static_assert(weekday{June/21/2016} == Tuesday);
Copy the code
This is the most popular JSON syntax in JavaScript.
Direct use of hardware
- Function – Uses the memory stack framework directly
- Coroutines – Use memory invocation frameworks
coroutines
Coroutines are generators and pipes that rely primarily on loading.
int main(a)
{
auto src = seq(2); / / infinity int sequence: 2,3,4,5,6,7,8,9,10,11,...
auto s = sieve(src); // filter nonprime numbers: 2,3,5,7,11...
auto t = take(s, 10 '000); // get the first 10000 primes: 2,3,5... 104729
print(t); // Prints prime numbers
}
Copy the code
I will not refer to the translation of this PPT, you will understand.
This is the output of the coroutine.
Using makes it easier for us to redefine types!
The core goal of coroutines is simple asynchronous programming.
library
C++20 makes it easy to use libraries written in any other programming language when C++ can use libraries in other programming languages besides its own standard library.
The standard library, like the Boost Qt framework library, is so good.
Time to deal with
I do not refer to the translation of these two PPT, because it is easy to understand.
What is C++20?
C++20, the most important release since C++11, has the following features:
- Simple, elegant, faster coding and faster compilation
- Modular programming
- Concept definition
- coroutines
- Specify the scope of
- The date of
- The scope of span
- Better compile-time programming support
- Lots of little features, but they’re really important
- C++ is a general-purpose programming language that defines and implements lightweight abstractions.
- Not a complex feature pack
- It’s a set of ideas
- It is a set of design principles
- It goes through an evolutionary process… ->C++98->C++11->C++14->C++17->C++20->…
- It is a standard WG21(C++ standard protocol)
C++20 and later features
Additional features in C++23:
- Standard module
- A library that supports coroutines
- Actuators and network programming
There might be
- The static reflection
- Design pattern matching
** What it means that you may not be sensitive to static reflection and design pattern matching. If C++ implements reflection and the C++ language itself can match design patterns, it means that the current favorite Java language should be out of the way.
conclusion
C++20 is awesome!
Although, it’s 2021 and we haven’t released a version of VS 2020 yet. However, we are looking forward to the C++20 version being put into actual development.
The last
Remember to give dashu ❤️ attention + like + collect + comment + forward ❤️
Author: Lao Jiu School – technology big millet
Copyright belongs to the author. Commercial reprint please contact the author for authorization, non-commercial reprint please indicate the source.