Hier sind die Folien (+Bugfixes) von meinem Vortrag über modernes C++ auf der GPN14 als HTML-Dokument.
###C++
1983 - Bjarne Stroustrup bolts everything he’s ever heard of onto C to create C++. The resulting language is so complex that programs must be sent to the future to be compiled by the Skynet artificial intelligence. Build times suffer. Skynet’s motives for performing the service remain unclear but spokespeople from the future say “there is nothing to be concerned about, baby,” in an Austrian accented monotones. There is some speculation that Skynet is nothing more than a pretentious buffer overrun.
— James Iry: A Brief, Incomplete, and Mostly Wrong History of Programming Languages
###RAII
void safe_fun(std::string path) {
"file.txt"; //can throw
path += std::ifstream file{path};
//can throw
util::enforce_opened(file, path); // string-reallocation can throw:
for (std::string line; getline(file, line);) {
std::lock_guard<std::mutex> guard{global_mutex};
//can throw
global_vec.emplace_back(line);
} }
###Ownership
int main() {
std::string str; // owner = main
"foobar"; // changes by owner are fine
str += // main() stays owner, should only
fun(str); // pass str by const reference
// cleanup by main(), because it is the owner
}
###Low- vs. Highlevel
###Highlevel = schnell
###Bibliotheken
std::string
statt eingebautem Stringsstd::vector
statt verwendbaren eingebauten Arraysstd::tuple
statt eingebauter Tupel###Pass-by-Value vs. Pass-by-Reference
class my_class {
public:
std::string str): str{std::move(str)} {}
my_class(// my_class(const std::string& str): str{str} {}
private:
std::string str;
};
int main() {
"some pretty long string"};
my_class var1{std::string str = "long string with many chars";
my_class var2{str};std::move(str)};
my_class var3{ }
###Metaprogrammierung
###Übersicht
###Literale
0b0011 == 3
1'000'000'000
###Lambdas
auto a, auto b){return a+b;} [](
std::move(ptr)] {return ptr->foo();} [ptr =
###Funktionen
auto fun() {return 42;}
constexpr
-Funktionenconstexpr unsigned exp(unsigned b, unsigned e) {
unsigned returnval = 1;
for(unsigned i = 0; i < e; ++i) {
returnval *= b;
}return returnval;
}
###Templates
template<typename T> constexpr T pi = 3.14159;
###Sonstige Kernsprachenfeatures
deprecated("use new_good_function instead")]]
[[int* ancient_bad_function();
std::array<int, 3> arr = {1, 2, 3};
std::make_unique
// efficient thanks to perfect forwarding:
auto ptr = std::make_unique<std::string>("foo");
new
again“//spot the bug:
void f(std::unique_ptr<int>, std::unique_ptr<int>);
std::unique_ptr<int>(new int(3)),
f(std::unique_ptr<int>(new int(4)));
std::make_unique<int>(3),
f(std::make_unique<int>(4));
std::literals::foo_literals
literals
und foo_literals
sind inline-Namensräumeusing namespace std::literals
using namespace std::string_literals
using namespace std::literals;
int main() {
auto s = "foo"s; // std::string
auto seconds = 3s; //std::chrono::seconds
}
std::equal
, std::mismatch
, und std::is_permutation
std::vector<int> vec1 = {1,2,3}, vec2 = {1,2,3,4};
// oops: returns true
std::equal(begin(vec1), end(vec1), begin(vec2));
// oops: UB
std::equal(begin(vec2), end(vec2), begin(vec1));
// correct: returns false
std::equal(begin(vec1), end(vec1),
begin(vec2), end(vec2));
std::stringstream ss;
std::string str;
"foo bar";
ss << // "foo" ss >> str;
std::quoted("foo bar");
ss << std::quoted(str); // "foo bar" ss >>
std::quoted("x\"\\$ y") // -> "x\"\\$ y"
std::quoted("x\"\\$ y", '$', '%') // -> $x"\%$ y$
using std::string;
std::tuple<string, string, int> t("foo", "bar", 7);
int i = get<int>(t); // i == 7
int j = get<2>(t); // Equivalent to the above: j == 7
// Compile-time error string s = get<string>(t);
std::exchange
template<typename T, typename U=T>
T exchange(T& obj, U&& new_val) {std::move(obj);
T old_val = std::forward<U>(new_val);
obj = return old_val;
}
The benefit isn’t huge, but neither is the specification cost.
std::shared_timed_mutex
std::shared_lock
using namespace std::literals;
std::shared_timed_mutex mut;
using guard = std::shared_lock<std::shared_timed_mutex>;
void reader() {
if(guard g{mut, 100us}){
read();else {
}
panic();
} }
#include <algorithm>
#include <list>
int main() {
std::list<int> lst = {4, 3, 2, 1};
sort(begin(lst), end(lst)); }
error: no matching call to ‘sort(forward_list<int>&)’
note: candidate is ‘sort(C& container)’
note: where C = forward_list<int>
note: template constraints not satisfied
note: ‘C’ is not a/an ‘Sortable’ type since
note: ‘c[n]’ is not valid syntax
void fun(int arg, int& ret1, int& ret2);
std::tuple<int, int> fun(int arg);
std::tie
:long val; // sic
std::tie(val, std::ignore) = fun(42);
std::lexicographical_compare
und std::equal
std::tie
:struct col {
unsigned char r, g, b;
};
bool operator<(const col& l, const col& r) {
return std::tie(l.r, l.g, l.b)
std::tie(r.r, r.g, r.b);
< }
void fun1(const std::map<std::string, int>& map) {
for(const std::pair<std::string, int>& pair: map) {
std::cout << pair.first << ": "
'\n';
<< pair.second <<
}
}
void fun2(const std::map<std::string, int>& map) {
for(auto&& pair: map) {
std::cout << pair.first << ": "
'\n';
<< pair.second <<
} }
If you want to improve the code quality in your organization, replace all your coding guidelines with one goal:
No raw loops!
std::rotate(begin(container), sub_range_begin,
sub_range_end);
std::stable_partition(begin, target, std::not1(pred));
std::stable_partition(target, end, pred);
std::vector vec(n - 3);
std::iota(begin(vec), end(vec), 3);
int main() {
std::vector<int> vec;
// foo::begin(foo::bar) exists
foo::bar x; // bla::begin(bla::blub) doesn't exist
bla::blub y;
using std::begin;
auto it1 = begin(vec); // -> std::begin
auto it2 = begin(x); // -> foo::begin
auto it3 = begin(y); // -> std::begin
}
std::terminate
oder std::abort
vielleicht besserdynamic_cast
, …)std::terminate()
main()
sollte mindestens std::runtime_error
fangen:int main() try {
do_something();catch(std::runtime_error& e) {
} std::cerr << "Runtime-error: " << e.what() << '\n';
}
struct base {
virtual std::unique_ptr<base> clone() const = 0;
virtual ~base = default
};
template<typename T> class wrapper: base {
T value;virtual std::unique_ptr<base> clone() const override {
return std::make_unique<wrapper<T>>(value);
} };
$YOUR_FAVOURITE_TUTORIAL
https://github.com/FlorianJW/cpp_tut
foo.h
bitte für C reservieren (foo.H
nur zum trollen)snake_case
, nicht PascalCase
std::endl
std::endl
leert den Puffer und ist sonst identisch zu '\n'
std::cout << "bad" << std::endl;
std::cout << "good\n";
std::cerr << "NEVER what you want!" << std::endl;
std::cerr << "since std::cerr is unbuffered.\n";
'\n'
plattformspezifischer Zeilenumbruch)//foo.hpp:
class foo {
foo();virtual ~foo();
// stuff
};
//foo.cpp
foo::foo() {} foo::~foo() {}
// better: Rule of 5
class foo {
default;
foo() = virtual ~foo() = default;
const foo&) = default;
foo(default;
foo(foo&&) = operator(const foo&) = default;
foo& operator(foo&&) = default;
foo& // stuff
};
// usually best: Rule of zero
class foo{
// stuff
};
class math {
static double sin(double);
static double cos(double);
static double tan(double);
};
int main() {
// err...
math m; auto m2 = m; // You can copy a math?
assert(&m != nullptr); // math has an adress?
}
class searcher {
std::size_t search(const std::string& haystack,
char needle) const {
/* ... */
} };
std::size_t search(const std::string& haystack,
char needle) { /* ... */ }