cpp23-listings-README-onepage.md
Listings of Gesamt.docx
This is the list of listings on one page. You can also view a linked summary.
Listing 1.1: Ein kleines Formatbeispiel
Book listing lst-0001-book.cpp:
// https://godbolt.org/z/jrqEGvh1M
#include <iostream> // cout
#include <memory> // make_shared
int main() { // ein Kommentar
std::cout << "Blopp\n"; // hervorgehoben
Typ feh-ler(args); // (ERR) Zeile mit einem Fehler
if consteval { // auf C++23-Features weise ich hin
sin(55); }
for(;;) break; // andere Markierung, zur Unterscheidung oder Hervorhebung
}
Godbolt Listing lst-0001-godb.cpp, https://godbolt.org/z/jrqEGvh1M:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/jrqEGvh1M
#include <iostream> // cout
#include <memory> // make_shared
int main() { // ein Kommentar
std::cout << "Blopp\n"; // hervorgehoben
Typ feh-ler(args); // (ERR) Zeile mit einem Fehler
if consteval { // auf C++23-Features weise ich hin
sin(55); }
for(;;) break; // andere Markierung, zur Unterscheidung oder Hervorhebung
}
Listing 2.1: Jede Fibonacci-Zahl ist die Summe der beiden Zahlen davor.
Book listing lst-0002-book.cpp:
// https://godbolt.org/z/aEvcPWzn5
// modern101.cpp : Fibonacci-Konsole
#include <iostream>
int fib(int n) {
return n<=1 ? n : fib(n-2) + fib(n-1);
}
int main() {
std::cout << "Die wievielte Fibonacci-Zahl? ";
int n = 0;
std::cin >> n;
std::cout << "fib(" << n << ")=" << fib(n) << "\n";
}
Godbolt Listing lst-0002-godb.cpp, https://godbolt.org/z/aEvcPWzn5:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/aEvcPWzn5
// modern101.cpp : Fibonacci-Konsole
#include <iostream>
int fib(int n) {
return n<=1 ? n : fib(n-2) + fib(n-1);
}
int main() {
std::cout << "Die wievielte Fibonacci-Zahl? ";
int n = 0;
std::cin >> n;
std::cout << "fib(" << n << ")=" << fib(n) << "\n";
}
Listing 2.2: Eine zügig erstellte Tabelle von Fibonacci-Zahlen
Book listing lst-0003-book.cpp:
// https://godbolt.org/z/Tbx6qdrfx
// modern102.cpp : Fibonacci-Konsole
#include <iostream>
#include <map>
int fib(int n) {
static std::map<int, int> table{};
table[n] = n<=1 ? n : table[n-2] + table[n-1];
return table[n];
}
int main() {
std::cout << "Wie viele Fibonacci-Zahlen? ";
int n = 0;
std::cin >> n;
for (int i = 1; i <= n; ++i)
std::cout << "fib(" << i << ")=" << fib(i) << "\n";
}
Godbolt Listing lst-0003-godb.cpp, https://godbolt.org/z/Tbx6qdrfx:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Tbx6qdrfx
// modern102.cpp : Fibonacci-Konsole
#include <iostream>
#include <map>
int fib(int n) {
static std::map<int, int> table{};
table[n] = n<=1 ? n : table[n-2] + table[n-1];
return table[n];
}
int main() {
std::cout << "Wie viele Fibonacci-Zahlen? ";
int n = 0;
std::cin >> n;
for (int i = 1; i <= n; ++i)
std::cout << "fib(" << i << ")=" << fib(i) << "\n";
}
Listing 3.2: (C++) In C++ hat man statt Referenzen erst einmal Werte.
Book listing lst-0004-book.cpp:
Data data{5};
Data mehr{6};
data = mehr;
mehr.value = 7;
cout << data.value << '\n'; // immer noch 6
Listing 3.3: (C++) Modernes C++ mit Heapspeicher nutzt Hilfsklassen wie shared_ptr.
Book listing lst-0005-book.cpp:
// https://godbolt.org/z/WM11Gs6sz
auto data = make_shared<Data>(5);
auto mehr = make_shared<Data>(6);
data = mehr;
mehr->value = 7;
cout << data->value << '\n'; // jetzt auch 7
Godbolt Listing lst-0005-godb.cpp, https://godbolt.org/z/WM11Gs6sz:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/WM11Gs6sz
auto data = make_shared<Data>(5);
auto mehr = make_shared<Data>(6);
data = mehr;
mehr->value = 7;
cout << data->value << '\n'; // jetzt auch 7
Listing 3.4: (C++) Ohne moderne C++-Mittel muss man besonders auf den Zeigerbesitz achten.
Book listing lst-0006-book.cpp:
// https://godbolt.org/z/Ee7eqq1MY
Data* dataOwner = new Data(5);
Data* data = dataOwner;
Data* mehr = new Data(6);
data = mehr;
mehr->value = 7;
cout << data->value << '\n'; // jetzt auch 7
/* selbst wegräumen */
delete mehr;
delete dataOwner;
Godbolt Listing lst-0006-godb.cpp, https://godbolt.org/z/Ee7eqq1MY:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Ee7eqq1MY
Data* dataOwner = new Data(5);
Data* data = dataOwner;
Data* mehr = new Data(6);
data = mehr;
mehr->value = 7;
cout << data->value << '\n'; // jetzt auch 7
/* selbst wegräumen */
delete mehr;
delete dataOwner;
Listing 3.6: (C++) const kann den Wert oder die Referenz schützen.
Book listing lst-0007-book.cpp:
// https://godbolt.org/z/Moe5M7sK8
Data const * data = new Data(5);
data->value = 7; // dieses const schützt Data
data = new Data(6); // Zeiger neu zuweisen ist okay
Data * const mehr = new Data(8);
mehr->value = 9; // jetzt okay
mehr = new Data(10); // Referenz ist geschützt
Godbolt Listing lst-0007-godb.cpp, https://godbolt.org/z/Moe5M7sK8:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Moe5M7sK8
Data const * data = new Data(5);
data->value = 7; // dieses const schützt Data
data = new Data(6); // Zeiger neu zuweisen ist okay
Data * const mehr = new Data(8);
mehr->value = 9; // jetzt okay
mehr = new Data(10); // Referenz ist geschützt
Listing 4.7: Ein sehr einfaches C++-Programm
Book listing lst-0008-book.cpp:
// https://godbolt.org/z/Mdj7bGvar
#include <iostream> // Module/Bibliotheken einbinden
int main() // main() ist der Beginn des Programms
{
int wert = 100; // Variable mit Anfangswert
std::cout << "Teiler von " << wert << " sind:\n"; // Ausgabe von Text
for(int teiler=1; teiler <= wert; teiler = teiler+1) // Schleife von 1 bis 100
{ // hier beginnt der Wiederholungsteil
if(wert % teiler == 0) // Test für eine bedingte Ausführung
std::cout << teiler << ", "; // nur bei positivem Test
} // Ende der Schleife
std::cout << "\n"; // einmalige Ausgabe
return 0; // bedeutet in main() Programmende
} // Ende von main()
Godbolt Listing lst-0008-godb.cpp, https://godbolt.org/z/Mdj7bGvar:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Mdj7bGvar
#include <iostream> // Module/Bibliotheken einbinden
int main() // main() ist der Beginn des Programms
{
int wert = 100; // Variable mit Anfangswert
std::cout << "Teiler von " << wert << " sind:\n"; // Ausgabe von Text
for(int teiler=1; teiler <= wert; teiler = teiler+1) // Schleife von 1 bis 100
{ // hier beginnt der Wiederholungsteil
if(wert % teiler == 0) // Test für eine bedingte Ausführung
std::cout << teiler << ", "; // nur bei positivem Test
} // Ende der Schleife
std::cout << "\n"; // einmalige Ausgabe
return 0; // bedeutet in main() Programmende
} // Ende von main()
Listing 4.8: Dieses Programm fragt seine Benutzer nach einer Zahl.
Book listing lst-0016-book.cpp:
// https://godbolt.org/z/d7Yjr9jdb
#include <iostream> // für std::cin, std::cout, std::endl
#include <string> // std::stoi
void berechne(int n) { // eine eigene Funktion
using namespace std; // für std::cout und std::endl
/* Teiler ausgeben */
cout << "Teiler von " << n << " sind:\n";
if(n == 0) { cout << "0\n"; return; } // 0 ist Teiler von 0
for(int teiler=1; teiler <= n; ++teiler) { // statt teiler=teiler+1
if(n % teiler == 0)
cout << teiler << ", ";
}
cout << endl;
}
int main(int argc, const char* argv[]) { // Argumente für main
/* Zahl ermitteln */
int wert = 0;
if(argc<=1) {
std::cout << "Geben Sie eine Zahl ein: ";
std::cin >> wert; // in Variable wert lesen
if(!std::cin) { // prüfen, ob lesen klappte
return 1; // Fehler bei Benutzereingabe
}
} else {
wert = std::stoi(argv[1]);
}
berechne(wert); // Funktionsaufruf
return 0;
}
Godbolt Listing lst-0016-godb.cpp, https://godbolt.org/z/d7Yjr9jdb:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/d7Yjr9jdb
#include <iostream> // für std::cin, std::cout, std::endl
#include <string> // std::stoi
void berechne(int n) { // eine eigene Funktion
using namespace std; // für std::cout und std::endl
/* Teiler ausgeben */
cout << "Teiler von " << n << " sind:\n";
if(n == 0) { cout << "0\n"; return; } // 0 ist Teiler von 0
for(int teiler=1; teiler <= n; ++teiler) { // statt teiler=teiler+1
if(n % teiler == 0)
cout << teiler << ", ";
}
cout << endl;
}
int main(int argc, const char* argv[]) { // Argumente für main
/* Zahl ermitteln */
int wert = 0;
if(argc<=1) {
std::cout << "Geben Sie eine Zahl ein: ";
std::cin >> wert; // in Variable wert lesen
if(!std::cin) { // prüfen, ob lesen klappte
return 1; // Fehler bei Benutzereingabe
}
} else {
wert = std::stoi(argv[1]);
}
berechne(wert); // Funktionsaufruf
return 0;
}
Listing 4.9: Ein sehr außergewöhnlich formatiertes Stück Quellcode
Book listing lst-0017-book.cpp:
// https://godbolt.org/z/eWfGbv1dG
# include <iostream> // # muss am Zeilenanfang stehen
int main(
){
std::cout
<<"Dies ist "
"Text mit <Klammern>\n" // String-Literal unterbrochen durch neue Zeile
;
/*Typ:*/ int
/*Variable:*/ ein_Wert
/*Init:*/ = 100; // innere Kommentare
std::cout<<ein_Wert<<"\n";} // keine Leerzeichen
Godbolt Listing lst-0017-godb.cpp, https://godbolt.org/z/eWfGbv1dG:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/eWfGbv1dG
# include <iostream> // # muss am Zeilenanfang stehen
int main(
){
std::cout
<<"Dies ist "
"Text mit <Klammern>\n" // String-Literal unterbrochen durch neue Zeile
;
/*Typ:*/ int
/*Variable:*/ ein_Wert
/*Init:*/ = 100; // innere Kommentare
std::cout<<ein_Wert<<"\n";} // keine Leerzeichen
Listing 4.10: Kommentare mit / und / können über mehrere Zeilen gehen oder eine Programmzeile auch unterbrechen.
Book listing lst-0018-book.cpp:
int main() {
/* Mein erstes Programm. Es wurde
geschrieben von Max Muster.*/
return /* Die Null des Erfolgs */ 0;
}
Listing 4.11: Eine eigene C++-Funktion
Book listing lst-0021-book.cpp:
// https://godbolt.org/z/qWxq4KEKr
void berechne(int n) { // eine eigene Funktion
using namespace std; // für std::cout und std::endl
/* Teiler ausgeben */
cout << "Teiler von " << n << " sind:\n";
for(int teiler=1; teiler <= n; ++teiler) { // statt teiler=teiler+1
if(n % teiler == 0)
cout << teiler << ", ";
}
cout << endl;
}
Godbolt Listing lst-0021-godb.cpp, https://godbolt.org/z/qWxq4KEKr:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/qWxq4KEKr
void berechne(int n) { // eine eigene Funktion
using namespace std; // für std::cout und std::endl
/* Teiler ausgeben */
cout << "Teiler von " << n << " sind:\n";
for(int teiler=1; teiler <= n; ++teiler) { // statt teiler=teiler+1
if(n % teiler == 0)
cout << teiler << ", ";
}
cout << endl;
}
Listing 4.12: Präfixoperatoren werden vor der Berechnung ausgeführt.
Book listing lst-0022-book.cpp:
// https://godbolt.org/z/4Mr6fnaEr
#include <iostream> // cout
int main() {
int basis = 2;
int index = 10;
int zahl = 3 * (basis + ++index) - 1; // zuerst wird index erhöht
std::cout << zahl << '\n'; // Ausgabe: 38
}
Godbolt Listing lst-0022-godb.cpp, https://godbolt.org/z/4Mr6fnaEr:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/4Mr6fnaEr
#include <iostream> // cout
int main() {
int basis = 2;
int index = 10;
int zahl = 3 * (basis + ++index) - 1; // zuerst wird index erhöht
std::cout << zahl << '\n'; // Ausgabe: 38
}
GodboltId:r5hjrqqK9
Book listing lst-0024-book.cpp:
// https://godbolt.org/z/r5hjrqqK9
#include <iostream>
int main() {
int var = 10;
var += 2;
var *= 3;
var /= 4;
var -= 5;
std::cout << var << "\n"; // ergibt 4
}
Godbolt Listing lst-0024-godb.cpp, https://godbolt.org/z/r5hjrqqK9:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/r5hjrqqK9
#include <iostream>
int main() {
int var = 10;
var += 2;
var *= 3;
var /= 4;
var -= 5;
std::cout << var << "\n"; // ergibt 4
}
Listing 4.13: Ein Programm, das nur aus main und return besteht
Book listing lst-0025-book.cpp:
int main() {
if(2 < 1) return 1; // ein return
return 0; // anderes return
} // Ende von main
Listing 4.14: Hier setzen Sie nur die äußeren geschweiftenKlammern.
Book listing lst-0026-book.cpp:
for(int teiler=1; teiler <= n; ++teiler) // for-Schleife
{ // Beginn des Schleifenblocks
if(n % teiler == 0)
std::cout << teiler << ", ";
} // Ende des Schleifenblocks
Listing 4.15: So sieht es aus, wenn Sie alle geschweiften Klammern setzen.
Book listing lst-0027-book.cpp:
if(argc<=1) { // Beginn der if-Anweisung
std::cout << "Geben Sie eine Zahl ein: ";
std::cin >> zahl;
if(!std::cin) {
return 1;
}
} else {
wert = std::stoi(argv[1]);
} // Ende der if-Anweisung
Listing 4.16: Das »if« ist eine Anweisung und benötigt eigentlich keine geschweiften Klammern.
Book listing lst-0028-book.cpp:
for(int teiler=1; teiler <= wert; ++teiler)
if(wert % teiler == 0)
std::cout << teiler << ", ";
Listing 4.17: Setzen Sie besser auch einzelne Anweisungen in geschweifte Klammern.
Book listing lst-0030-book.cpp:
for(int teiler=1; teiler <= wert; ++teiler) {
if(wert % teiler == 0) {
std::cout << teiler << ", ";
}
}
Listing 4.18: Zuweisung des Ergebnisses eines Funktionsaufrufs
Book listing lst-0033-book.cpp:
wert = std::stoi(argv[1]);
Listing 4.19: Zuweisung des Ergebnisses einer Berechnung
Book listing lst-0034-book.cpp:
teiler = teiler + 1
Listing 4.20: Eine Zuweisung ist ein Ausdruck mit dem Typ der zugewiesenen Variablen.
Book listing lst-0035-book.cpp:
// https://godbolt.org/z/bh1MsPhje
#include <iostream>
int main() {
int a = 3;
int b = 7 + (a = 12) + 6; // enthält eine Zuweisung
std::cout << a << std::endl;
}
Godbolt Listing lst-0035-godb.cpp, https://godbolt.org/z/bh1MsPhje:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/bh1MsPhje
#include <iostream>
int main() {
int a = 3;
int b = 7 + (a = 12) + 6; // enthält eine Zuweisung
std::cout << a << std::endl;
}
Listing 4.21: Der Compiler hilft, korrekte Programme zu schreiben, indem er die Typen überprüft.
Book listing lst-0036-book.cpp:
// https://godbolt.org/z/9943MfExc
#include <vector>
class Image {
std::vector<char> data_;
public:
void load(const char* filename); // lädt Bilddaten
};
class Screen {
public:
void show(Image& image); // (ERR) image sollte const sein
};
void paint(Screen &screen, const Image& image) {
screen.show(image);
}
int main() {
Image image {};
image.load("peter.png");
Screen screen {};
paint(screen, image);
}
Godbolt Listing lst-0036-godb.cpp, https://godbolt.org/z/9943MfExc:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/9943MfExc
#include <vector>
class Image {
std::vector<char> data_;
public:
void load(const char* filename); // lädt Bilddaten
};
class Screen {
public:
void show(Image& image); // (ERR) image sollte const sein
};
void paint(Screen &screen, const Image& image) {
screen.show(image);
}
int main() {
Image image {};
image.load("peter.png");
Screen screen {};
paint(screen, image);
}
Listing 4.22: Variablen vom Typ bool können das Ergebnis eines Vergleichs zwischenspeichern.
Book listing lst-0037-book.cpp:
// https://godbolt.org/z/zK9Ke9n48
#include <iostream> // cout
int main(int argc, const char* argv[]) {
bool mitParametern = argc > 1; // Vergleichsergebnis zwischengespeichert
if(mitParametern) { // … und verwendet
std::cout << "Sie haben das Programm mit Parametern aufgerufen.\n";
}
return 0;
}
Godbolt Listing lst-0037-godb.cpp, https://godbolt.org/z/zK9Ke9n48:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/zK9Ke9n48
#include <iostream> // cout
int main(int argc, const char* argv[]) {
bool mitParametern = argc > 1; // Vergleichsergebnis zwischengespeichert
if(mitParametern) { // … und verwendet
std::cout << "Sie haben das Programm mit Parametern aufgerufen.\n";
}
return 0;
}
Listing 4.23: So können Sie einen C++-string als Literal in den Quellcode schreiben.
Book listing lst-0039-book.cpp:
// https://godbolt.org/z/chTTqPjrM
#include <string>
#include <iostream>
int main() {
std::cout << "C-Zeichenkettenliteral\n";
// using std::literals::string_literals::operator""s;
// using namespace std::string_literals;
// using namespace std::literals::string_literals;
using namespace std::literals;
std::cout << "Echter string\n"s;
}
Godbolt Listing lst-0039-godb.cpp, https://godbolt.org/z/chTTqPjrM:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/chTTqPjrM
#include <string>
#include <iostream>
int main() {
std::cout << "C-Zeichenkettenliteral\n";
// using std::literals::string_literals::operator""s;
// using namespace std::string_literals;
// using namespace std::literals::string_literals;
using namespace std::literals;
std::cout << "Echter string\n"s;
}
Listing 4.24: Seit C++17 bestimmt der Compiler die Typparameter von Klassentemplates anhand der Konstruktorargumente.
Book listing lst-0041-book.cpp:
// https://godbolt.org/z/GbbcnYbqv
std::vector vec { 1, 2, 3 }; // statt vector<int>
std::tuple tpl { 5, 'x' }; // statt tuple<int,char>
std::shared_ptr<int> ptr { new int(5) };
std::shared_ptr ptr2 { ptr }; // statt shared_ptr<int>
Godbolt Listing lst-0041-godb.cpp, https://godbolt.org/z/GbbcnYbqv:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/GbbcnYbqv
std::vector vec { 1, 2, 3 }; // statt vector<int>
std::tuple tpl { 5, 'x' }; // statt tuple<int,char>
std::shared_ptr<int> ptr { new int(5) };
std::shared_ptr ptr2 { ptr }; // statt shared_ptr<int>
Listing 4.25: Manchen Variablen können Sie nichts zuweisen, Sie können sie nur initialisieren.
Book listing lst-0042-book.cpp:
int main() {
const int fest = 33; // Initialisierung als Konstante
fest = 80; // (ERR) eine Zuweisung ist unmöglich
}
Listing 4.26: Statt des = können Sie {…} zur Initialisierung verwenden.
Book listing lst-0043-book.cpp:
int index = 1; // alter Stil, sieht wie eine Zuweisung aus
int zaehler { 1 }; // C++11-Stil, eindeutig eine Initialisierung
int counter = { 1 }; // beim C++11-Stil ist das »=« optional und wird ignoriert
Listing 4.27: Sie können einen Namensraum einbinden, um Programmtext kürzer zu machen.
Book listing lst-0050-book.cpp:
#include <iostream> // für std::cin, std::cout, std::endl
#include <string> // für std::stoi
void berechne(int n) {
using namespace std; // für std::cout und std::endl
/* Teiler ausgeben */
cout << "Teiler von " << n << " sind:\n"; // cout statt std::cout
for(int teiler=1; teiler <= n; ++teiler) {
if(n % teiler == 0)
cout << teiler << ", "; // cout statt std::cout
}
cout << endl;
}
Listing 4.28: »using namespace« können Sie auch global verwenden, sollten es aber selten tun.
Book listing lst-0051-book.cpp:
#include <iostream>
#include <string>
using namespace std; // (ERR) wirkt sich global aus; klappt, ist aber kritisch
void berechne(int n) {
/* Teiler ausgeben */
cout << "Teiler von " << n << " sind:\n";
// …
}
// … auch in weiteren Funktionen …
Listing 4.29: Holen Sie sich mit »using« einzelne Bezeichner.
Book listing lst-0052-book.cpp:
#include <iostream> // cin, cout, endl
using std::endl; // gilt global in dieser Datei
void berechne(int n) {
using std::cout; // gilt lokal in dieser Funktion
/* Teiler ausgeben */
cout << "Teiler von " << n << " sind:\n";
for(int teiler=1; teiler <= n; ++teiler) {
if(n % teiler == 0)
cout << teiler << ", ";
}
cout << endl;
}
Listing 4.30: Arithmetische Operatoren in der Anwendung
Book listing lst-0053-book.cpp:
// https://godbolt.org/z/cEGGfoeT7
#include <iostream>
int main() {
std::cout << "3+4*5+6=" << 3+4*5+6 << "\n"; // Punkt vor Strich; = 29
std::cout << "(3+4)*(5+6)=" << (3+4)*(5+6) << "\n"; // Klammern; = 77
std::cout << "22/7=" << 22/7 << " Rest " << 22%7 << "\n"; // 22/7 = 3 Rest 1
for(int n=0; n < 10; ++n) {
std::cout << -2*n*n + 13*n - 4 << " "; // mit unärem Minus
}
std::cout << "\n";
// Ausgabe: –4 7 14 17 16 11 2 –11 –28 –49
}
Godbolt Listing lst-0053-godb.cpp, https://godbolt.org/z/cEGGfoeT7:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/cEGGfoeT7
#include <iostream>
int main() {
std::cout << "3+4*5+6=" << 3+4*5+6 << "\n"; // Punkt vor Strich; = 29
std::cout << "(3+4)*(5+6)=" << (3+4)*(5+6) << "\n"; // Klammern; = 77
std::cout << "22/7=" << 22/7 << " Rest " << 22%7 << "\n"; // 22/7 = 3 Rest 1
for(int n=0; n < 10; ++n) {
std::cout << -2*n*n + 13*n - 4 << " "; // mit unärem Minus
}
std::cout << "\n";
// Ausgabe: –4 7 14 17 16 11 2 –11 –28 –49
}
Listing 4.31: Programmierbeispiel für die Umwandlung einer Ganzzahl in eine Bitfolge
Book listing lst-0056-book.cpp:
// https://godbolt.org/z/nMcsbxvvv
#include <iostream>
void printBin(int x) {
while(x>0) { // fertig?
int a = x/2; // Division durch 2
int b = x%2; // Modulo, Rest der Division
std::cout << x <<" / 2 = " << a << ", Rest " << b<<'\n'; // Ausgabe
x = a;
}
}
int main() {
printBin(412);
}
Godbolt Listing lst-0056-godb.cpp, https://godbolt.org/z/nMcsbxvvv:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/nMcsbxvvv
#include <iostream>
void printBin(int x) {
while(x>0) { // fertig?
int a = x/2; // Division durch 2
int b = x%2; // Modulo, Rest der Division
std::cout << x <<" / 2 = " << a << ", Rest " << b<<'\n'; // Ausgabe
x = a;
}
}
int main() {
printBin(412);
}
GodboltId:TTjxzrYf3
Book listing lst-0057-book.cpp:
// https://godbolt.org/z/TTjxzrYf3
#include <iostream>
#include <bitset>
constexpr unsigned n_bits = sizeof(unsigned short)*8; // 8 Bit pro char
auto bits_umdrehen(unsigned val) -> unsigned short {
unsigned short ret = 0;
for (unsigned i = 0; i < n_bits; ++i ) {
ret = (ret << 1) | (val & 1); // eins zur Seite, unterstes evtl. setzen
val >>= 1; // eins in die andere Richtung
}
return ret;
}
void zeig(unsigned short val) {
std::bitset<n_bits> bits{val};
std::cout << val << "=" << bits << " -> ";
auto lav = bits_umdrehen(val);
std::bitset<n_bits> stib{lav};
std::cout << lav << "=" << stib << "\n";
}
int main() {
zeig(36u); // Ausgabe: 36=0000000000100100 -> 9216=0010010000000000
zeig(199u); // Ausgabe: 199=0000000011000111 -> 58112=1110001100000000
zeig(255u); // Ausgabe: 255=0000000011111111 -> 65280=1111111100000000
zeig(256u); // Ausgabe: 256=0000000100000000 -> 128=0000000010000000
}
Godbolt Listing lst-0057-godb.cpp, https://godbolt.org/z/TTjxzrYf3:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/TTjxzrYf3
#include <iostream>
#include <bitset>
constexpr unsigned n_bits = sizeof(unsigned short)*8; // 8 Bit pro char
auto bits_umdrehen(unsigned val) -> unsigned short {
unsigned short ret = 0;
for (unsigned i = 0; i < n_bits; ++i ) {
ret = (ret << 1) | (val & 1); // eins zur Seite, unterstes evtl. setzen
val >>= 1; // eins in die andere Richtung
}
return ret;
}
void zeig(unsigned short val) {
std::bitset<n_bits> bits{val};
std::cout << val << "=" << bits << " -> ";
auto lav = bits_umdrehen(val);
std::bitset<n_bits> stib{lav};
std::cout << lav << "=" << stib << "\n";
}
int main() {
zeig(36u); // Ausgabe: 36=0000000000100100 -> 9216=0010010000000000
zeig(199u); // Ausgabe: 199=0000000011000111 -> 58112=1110001100000000
zeig(255u); // Ausgabe: 255=0000000011111111 -> 65280=1111111100000000
zeig(256u); // Ausgabe: 256=0000000100000000 -> 128=0000000010000000
}
GodboltId:5hqanTeYh
Book listing lst-0059-book.cpp:
// https://godbolt.org/z/5hqanTeYh
#include <iostream>
#include <bitset> // hilft bei der Ausgabe von Zahlen als Bitfolge
int main() {
int a = 0;
for(int idx=0; idx<8; idx++) {
a <<= 2; // um zwei Bit nach links schieben: "…100"
a |= 1; // unterstes Bit setzen: "…1"
}
std::cout << std::bitset<16>(a) << "\n"; // 0101010101010101
std::cout << a << "\n"; // 21845
}
Godbolt Listing lst-0059-godb.cpp, https://godbolt.org/z/5hqanTeYh:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/5hqanTeYh
#include <iostream>
#include <bitset> // hilft bei der Ausgabe von Zahlen als Bitfolge
int main() {
int a = 0;
for(int idx=0; idx<8; idx++) {
a <<= 2; // um zwei Bit nach links schieben: "…100"
a |= 1; // unterstes Bit setzen: "…1"
}
std::cout << std::bitset<16>(a) << "\n"; // 0101010101010101
std::cout << a << "\n"; // 21845
}
GodboltId:xrMYz93WP
Book listing lst-0068-book.cpp:
// https://godbolt.org/z/xrMYz93WP
int main() {
for(int w1 = 1; w1 <= 6; ++w1) { // 1..6
for(int w2 = 0; w2 < 10; ++w2) { // 0..9
int max = w1 > w2 ? w1 : w2; // ternärer Operator
}
}
}
Godbolt Listing lst-0068-godb.cpp, https://godbolt.org/z/xrMYz93WP:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/xrMYz93WP
int main() {
for(int w1 = 1; w1 <= 6; ++w1) { // 1..6
for(int w2 = 0; w2 < 10; ++w2) { // 0..9
int max = w1 > w2 ? w1 : w2; // ternärer Operator
}
}
}
Listing 4.32: Mit Kommas in Klammern können Sie mehrere Ausdrücke verketten.
Book listing lst-0069-book.cpp:
// https://godbolt.org/z/rq66cWr3d
int main() {
int a = 0;
int b = 0;
for(int w1 = 1; w1 <= 6; ++w1) { // 1..6
for(int w2 = 0; w2 < 10; ++w2) { // 0..9
int max = w1 > w2 ? (a+=b , w1) :( b+=1 , w2); // Sequenzoperator
}
}
}
Godbolt Listing lst-0069-godb.cpp, https://godbolt.org/z/rq66cWr3d:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/rq66cWr3d
int main() {
int a = 0;
int b = 0;
for(int w1 = 1; w1 <= 6; ++w1) { // 1..6
for(int w2 = 0; w2 < 10; ++w2) { // 0..9
int max = w1 > w2 ? (a+=b , w1) :( b+=1 , w2); // Sequenzoperator
}
}
}
Listing 4.33: In for-Schleifen kann das Sequenzkomma nützlich sein.
Book listing lst-0070-book.cpp:
// https://godbolt.org/z/vd85f7rMj
#include <iostream>
int main() {
int arr[] = { 8,3,7,3,11,999,5,6,7 };
int len = 9;
for(int i=0, *p=arr; i<len && *p!=999; ++i, ++p) { // erst ++i, dann ++p
std::cout << i << ":" << *p << " ";
}
std::cout << "\n";
// Ausgabe: 0:8 1:3 2:7 3:3 4:11
}
Godbolt Listing lst-0070-godb.cpp, https://godbolt.org/z/vd85f7rMj:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/vd85f7rMj
#include <iostream>
int main() {
int arr[] = { 8,3,7,3,11,999,5,6,7 };
int len = 9;
for(int i=0, *p=arr; i<len && *p!=999; ++i, ++p) { // erst ++i, dann ++p
std::cout << i << ":" << *p << " ";
}
std::cout << "\n";
// Ausgabe: 0:8 1:3 2:7 3:3 4:11
}
Listing 4.34: Hier werden einige neue Datentypen verwendet.
Book listing lst-0074-book.cpp:
// https://godbolt.org/z/3Y65Ps6G4
#include <iostream> // cin, cout für Eingabe und Ausgabe
void eingabe(unsigned &gebTag_,
unsigned &gebMonat_,
unsigned &gebJahr_,
unsigned long long &steuernummer_,
double &koerperlaenge_)
{
/* Eingaben noch ohne gute Fehlerbehandlung... */
std::cout << "Geb.-Tag: "; std::cin >> gebTag_;
std::cout << "Geb.-Monat: "; std::cin >> gebMonat_;
std::cout << "Geb.-Jahr: "; std::cin >> gebJahr_;
std::cout << "Steuernummer: "; std::cin >> steuernummer_;
std::cout << "Koerperlaenge: "; std::cin >> koerperlaenge_;
}
int main() {
/* Daten */
unsigned gebTag_ = 0;
unsigned gebMonat_ = 0;
unsigned gebJahr_ = 0;
unsigned long long steuernummer_ = 0;
double koerperlaenge_ = 0.0;
/* Eingabe */
eingabe(gebTag_, gebMonat_, gebJahr_, steuernummer_, koerperlaenge_);
/* Berechnungen */
// …
}
Godbolt Listing lst-0074-godb.cpp, https://godbolt.org/z/3Y65Ps6G4:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/3Y65Ps6G4
#include <iostream> // cin, cout für Eingabe und Ausgabe
void eingabe(unsigned &gebTag_,
unsigned &gebMonat_,
unsigned &gebJahr_,
unsigned long long &steuernummer_,
double &koerperlaenge_)
{
/* Eingaben noch ohne gute Fehlerbehandlung... */
std::cout << "Geb.-Tag: "; std::cin >> gebTag_;
std::cout << "Geb.-Monat: "; std::cin >> gebMonat_;
std::cout << "Geb.-Jahr: "; std::cin >> gebJahr_;
std::cout << "Steuernummer: "; std::cin >> steuernummer_;
std::cout << "Koerperlaenge: "; std::cin >> koerperlaenge_;
}
int main() {
/* Daten */
unsigned gebTag_ = 0;
unsigned gebMonat_ = 0;
unsigned gebJahr_ = 0;
unsigned long long steuernummer_ = 0;
double koerperlaenge_ = 0.0;
/* Eingabe */
eingabe(gebTag_, gebMonat_, gebJahr_, steuernummer_, koerperlaenge_);
/* Berechnungen */
// …
}
Listing 4.35: Arithmetik mit Ganzzahlen
Book listing lst-0076-book.cpp:
// https://godbolt.org/z/ebPcdxzvj
#include <iostream>
int main() {
std::cout << 3 + 4 * 5 + 6 << "\n"; // 29
std::cout << 20/7 << " Rest " << 20%7 << "\n"; // 2 Rest 6
}
Godbolt Listing lst-0076-godb.cpp, https://godbolt.org/z/ebPcdxzvj:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/ebPcdxzvj
#include <iostream>
int main() {
std::cout << 3 + 4 * 5 + 6 << "\n"; // 29
std::cout << 20/7 << " Rest " << 20%7 << "\n"; // 2 Rest 6
}
Listing 4.36: Bitoperationen
Book listing lst-0077-book.cpp:
// https://godbolt.org/z/jeTs5Exqx
#include <iostream>
int main() {
unsigned a = 0b1111'0000; // 240
unsigned b = 0b0011'1100; // 60
std::cout << ( a | b ) << "\n"; // Bit-Oder: 252, in Bits 1111'1100
std::cout << ( a & b ) << "\n"; // Bit-Und: 48, in Bits 0011'0000
std::cout << ( a ^ b ) << "\n"; // Exklusiv-Oder: 204, in Bits 1100'1100
unsigned int c = 170; // in Bits 0..(24x0)..0'1010'1010
std::cout << ( ~c ) << "\n"; // Inv.: 4294967125, Bits: 1..(24x1)..1'0101'0101
}
Godbolt Listing lst-0077-godb.cpp, https://godbolt.org/z/jeTs5Exqx:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/jeTs5Exqx
#include <iostream>
int main() {
unsigned a = 0b1111'0000; // 240
unsigned b = 0b0011'1100; // 60
std::cout << ( a | b ) << "\n"; // Bit-Oder: 252, in Bits 1111'1100
std::cout << ( a & b ) << "\n"; // Bit-Und: 48, in Bits 0011'0000
std::cout << ( a ^ b ) << "\n"; // Exklusiv-Oder: 204, in Bits 1100'1100
unsigned int c = 170; // in Bits 0..(24x0)..0'1010'1010
std::cout << ( ~c ) << "\n"; // Inv.: 4294967125, Bits: 1..(24x1)..1'0101'0101
}
Listing 4.37: Indexvariablen können gut vom Typ »size_t« sein.
Book listing lst-0079-book.cpp:
// https://godbolt.org/z/zGso3xGcj
#include <vector>
#include <cstddef> // size_t
int main() {
std::vector<int> data = { 100, -4, 6'699, 88, 0, } ;
int sum = 0;
for(size_t idx = 0; idx < data.size(); ++idx) { // ein bestimmter int-Typ
sum += data[idx];
}
}
Godbolt Listing lst-0079-godb.cpp, https://godbolt.org/z/zGso3xGcj:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/zGso3xGcj
#include <vector>
#include <cstddef> // size_t
int main() {
std::vector<int> data = { 100, -4, 6'699, 88, 0, } ;
int sum = 0;
for(size_t idx = 0; idx < data.size(); ++idx) { // ein bestimmter int-Typ
sum += data[idx];
}
}
Listing 4.41: »double« kann Zahlen nicht immer exakt speichern. Rechnen und Vergleichen mit »==« ist ein Fehler.
Book listing lst-0080-book.cpp:
// https://godbolt.org/z/h86Wh5dbo
#include <iostream> // cout
#include <iomanip> // setprecision, etc.
#include <cmath> // fabs
using std::cout; // cout als Abkürzung für std::cout
int main() {
cout << std::fixed << std::setprecision(25); // für besser lesbare Ausgabe
// 0.1 und 0.01 kann double nicht exakt speichern
double x = 0.1 * 0.1;
cout << "0.1*0.1: " << x << "\n";
// Ausgabe: 0.1*0.1: 0.0100000000000000019428903
if(x == 0.01) { // (ERR) vergleichen Sie double niemals mit ==
cout << "Ja! x == 0.01" << "\n";
} else {
cout << "Oh-oh! x != 0.01" << "\n"; // Sie sehen diese Ausgabe
}
// Achtung vor allem beim Vergleich mit 0.0
double null = x - 0.01;
cout << "null: " << null << "\n";
// Ausgabe: null: 0.0000000000000000017347235
if(std::fabs(null) < 0.00000001) { // gegen ein "Epsilon"
cout << "Ja! null ist nahe 0.0" << "\n"; // Sie sehen diese Ausgabe
} else {
cout << "Oh-oh! null nicht nahe 0.0" << "\n";
}
// Brüche von 2er-Potenzen sind weniger kritisch
double y = 0.5 * 0.5;
cout << "0.5*0.5: " << y << "\n";
// Ausgabe: 0.5*0.5: 0.2500000000000000000000000
if(y == 0.25) { // hier klappt der gefährliche Vergleich ausnahmsweise
cout << "Ja! y == 0.25" << "\n"; // Sie sehen diese Ausgabe
} else {
cout << "Oh-oh! y != 0.25" << "\n";
}
//
return 0;
}
Godbolt Listing lst-0080-godb.cpp, https://godbolt.org/z/h86Wh5dbo:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/h86Wh5dbo
#include <iostream> // cout
#include <iomanip> // setprecision, etc.
#include <cmath> // fabs
using std::cout; // cout als Abkürzung für std::cout
int main() {
cout << std::fixed << std::setprecision(25); // für besser lesbare Ausgabe
// 0.1 und 0.01 kann double nicht exakt speichern
double x = 0.1 * 0.1;
cout << "0.1*0.1: " << x << "\n";
// Ausgabe: 0.1*0.1: 0.0100000000000000019428903
if(x == 0.01) { // (ERR) vergleichen Sie double niemals mit ==
cout << "Ja! x == 0.01" << "\n";
} else {
cout << "Oh-oh! x != 0.01" << "\n"; // Sie sehen diese Ausgabe
}
// Achtung vor allem beim Vergleich mit 0.0
double null = x - 0.01;
cout << "null: " << null << "\n";
// Ausgabe: null: 0.0000000000000000017347235
if(std::fabs(null) < 0.00000001) { // gegen ein "Epsilon"
cout << "Ja! null ist nahe 0.0" << "\n"; // Sie sehen diese Ausgabe
} else {
cout << "Oh-oh! null nicht nahe 0.0" << "\n";
}
// Brüche von 2er-Potenzen sind weniger kritisch
double y = 0.5 * 0.5;
cout << "0.5*0.5: " << y << "\n";
// Ausgabe: 0.5*0.5: 0.2500000000000000000000000
if(y == 0.25) { // hier klappt der gefährliche Vergleich ausnahmsweise
cout << "Ja! y == 0.25" << "\n"; // Sie sehen diese Ausgabe
} else {
cout << "Oh-oh! y != 0.25" << "\n";
}
//
return 0;
}
Listing 4.39: Mehrere Möglichkeiten, um »double«-Literale zu kennzeichnen
Book listing lst-0081-book.cpp:
// https://godbolt.org/z/f7T5Y6sd3
#include <iostream>
#include <iomanip> // fixed, setprecision
using std::cout; // abgekürzt cout
int main() {
cout << std::setprecision(2) << std::fixed; // zwei Nachkommastellen
cout << "1/4: " << 0.25 << "\n"; // Kommaschreibweise für double
// Ausgabe: 1/4: 0.25
cout << "2/4: " << 0.5 << "\n";
// Ausgabe: 2/4: 0.50
cout << "3/4: " << 0.75 << "\n";
// Ausgabe: 3/4: 0.75
cout << "4/4: " << 1 << " oder " << 1.0 << "\n"; // (ERR) erkennt 1 als int
// Ausgabe 4/4: 1 oder 1.00
cout << "1e0: " << 1e0 << "\n"; // wissenschaftliche Schreibweise
// Ausgabe: 1e0: 1.00
cout << "0x10.1p0: " << 0x10.1p0 << "\n"; // hexadezimale Schreibweise
// Ausgabe: 0x10.1p0: 16.06
}
Godbolt Listing lst-0081-godb.cpp, https://godbolt.org/z/f7T5Y6sd3:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/f7T5Y6sd3
#include <iostream>
#include <iomanip> // fixed, setprecision
using std::cout; // abgekürzt cout
int main() {
cout << std::setprecision(2) << std::fixed; // zwei Nachkommastellen
cout << "1/4: " << 0.25 << "\n"; // Kommaschreibweise für double
// Ausgabe: 1/4: 0.25
cout << "2/4: " << 0.5 << "\n";
// Ausgabe: 2/4: 0.50
cout << "3/4: " << 0.75 << "\n";
// Ausgabe: 3/4: 0.75
cout << "4/4: " << 1 << " oder " << 1.0 << "\n"; // (ERR) erkennt 1 als int
// Ausgabe 4/4: 1 oder 1.00
cout << "1e0: " << 1e0 << "\n"; // wissenschaftliche Schreibweise
// Ausgabe: 1e0: 1.00
cout << "0x10.1p0: " << 0x10.1p0 << "\n"; // hexadezimale Schreibweise
// Ausgabe: 0x10.1p0: 16.06
}
Listing 4.43: Fließkommaliterale werden irgendwann ungenau.
Book listing lst-0082-book.cpp:
// https://godbolt.org/z/6qfo4oYnr
#include <iostream>
#include <iomanip> // fixed, setprecision
int main() {
std::cout << std::setprecision(30) << std::fixed; // immer 30 Stellen
// ausgeben
std::cout << 1.111222333444555666777888999f << "\n"; // float-Literal
// Ausgabe: 1.111222386360168457031250000000
std::cout << 1.111222333444555666777888999 << "\n"; // double ist Default
// Ausgabe: 1.111222333444555676607023997349
std::cout << 1.111222333444555666777888999d << "\n"; // double-Literal
// Ausgabe: 1.111222333444555676607023997349
std::cout << 1.111222333444555666777888999L << "\n"; // long double
// Ausgabe: 1.111222333444555666740784227731
}
Godbolt Listing lst-0082-godb.cpp, https://godbolt.org/z/6qfo4oYnr:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/6qfo4oYnr
#include <iostream>
#include <iomanip> // fixed, setprecision
int main() {
std::cout << std::setprecision(30) << std::fixed; // immer 30 Stellen
// ausgeben
std::cout << 1.111222333444555666777888999f << "\n"; // float-Literal
// Ausgabe: 1.111222386360168457031250000000
std::cout << 1.111222333444555666777888999 << "\n"; // double ist Default
// Ausgabe: 1.111222333444555676607023997349
std::cout << 1.111222333444555666777888999d << "\n"; // double-Literal
// Ausgabe: 1.111222333444555676607023997349
std::cout << 1.111222333444555666777888999L << "\n"; // long double
// Ausgabe: 1.111222333444555666740784227731
}
Listing 4.44: Unter anderem können Sie mit »fpclassify« besondere Werte entdecken.
Book listing lst-0083-book.cpp:
// https://godbolt.org/z/v98fWc49E
#include <iostream>
#include <cmath> // fpclassify
#include <limits> // numeric_limits
#include <string>
std::string fpklass(double x) {
switch(std::fpclassify(x)) {
case FP_INFINITE: return "unendlich";
case FP_NAN: return "NaN";
case FP_NORMAL: return "normal";
case FP_SUBNORMAL: return "subnormal";
case FP_ZERO: return "Null";
default: return "unbekannt";
}
}
int main() {
const auto dmin = std::numeric_limits<double>::min();
std::cout
<<"1.0/0.0 ist "<<fpklass(1/0.0)<<'\n' // Ausgabe: 1.0/0.0 ist unendlich
<<"0.0/0.0 ist "<<fpklass(0.0/0.0)<<'\n' // Ausgabe: 0.0/0.0 ist NaN
<<"dmin/2 ist "<<fpklass(dmin/2)<<'\n' // Ausgabe: dmin/2 ist subnormal
<<"-0.0 ist "<<fpklass(-0.0)<<'\n' // Ausgabe: –0.0 ist null
<<"1.0 ist "<<fpklass(1.0)<<'\n'; // Ausgabe: 1.0 ist normal
}
Godbolt Listing lst-0083-godb.cpp, https://godbolt.org/z/v98fWc49E:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/v98fWc49E
#include <iostream>
#include <cmath> // fpclassify
#include <limits> // numeric_limits
#include <string>
std::string fpklass(double x) {
switch(std::fpclassify(x)) {
case FP_INFINITE: return "unendlich";
case FP_NAN: return "NaN";
case FP_NORMAL: return "normal";
case FP_SUBNORMAL: return "subnormal";
case FP_ZERO: return "Null";
default: return "unbekannt";
}
}
int main() {
const auto dmin = std::numeric_limits<double>::min();
std::cout
<<"1.0/0.0 ist "<<fpklass(1/0.0)<<'\n' // Ausgabe: 1.0/0.0 ist unendlich
<<"0.0/0.0 ist "<<fpklass(0.0/0.0)<<'\n' // Ausgabe: 0.0/0.0 ist NaN
<<"dmin/2 ist "<<fpklass(dmin/2)<<'\n' // Ausgabe: dmin/2 ist subnormal
<<"-0.0 ist "<<fpklass(-0.0)<<'\n' // Ausgabe: –0.0 ist null
<<"1.0 ist "<<fpklass(1.0)<<'\n'; // Ausgabe: 1.0 ist normal
}
GodboltId:We3oWrcWW
Book listing lst-0086-book.cpp:
// https://godbolt.org/z/We3oWrcWW
#include <iostream>
#include <cmath> // sqrt
#include <concepts> // floating_point
using std::min; using std::max; using std::floating_point;
template<floating_point T> T heron(T a, T b, T c) {
auto s = (a+b+c) / 2;
return sqrt(s*(s-a)*(s-b)*(s-c));
}
template<floating_point T> T kahan(T a, T b, T c) {
auto x = max(a,max(b,c));
auto y = max(min(a,b), min(max(a,b),c));
auto z = min(a,min(b,c));
return sqrt( (x+(y+z))*(z-(x-y))*(z+(x-y))*(x+(y-z)) )/4 ;
}
template<floating_point T> void dreieck(T a, T b, T c) {
std::cout << "heron: " << heron(a,b,c) << '\n';
std::cout << "kahan: " << kahan(a,b,c) << '\n';
}
int main() {
dreieck(3.0f, 4.0f, 5.0f);
}
Godbolt Listing lst-0086-godb.cpp, https://godbolt.org/z/We3oWrcWW:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/We3oWrcWW
#include <iostream>
#include <cmath> // sqrt
#include <concepts> // floating_point
using std::min; using std::max; using std::floating_point;
template<floating_point T> T heron(T a, T b, T c) {
auto s = (a+b+c) / 2;
return sqrt(s*(s-a)*(s-b)*(s-c));
}
template<floating_point T> T kahan(T a, T b, T c) {
auto x = max(a,max(b,c));
auto y = max(min(a,b), min(max(a,b),c));
auto z = min(a,min(b,c));
return sqrt( (x+(y+z))*(z-(x-y))*(z+(x-y))*(x+(y-z)) )/4 ;
}
template<floating_point T> void dreieck(T a, T b, T c) {
std::cout << "heron: " << heron(a,b,c) << '\n';
std::cout << "kahan: " << kahan(a,b,c) << '\n';
}
int main() {
dreieck(3.0f, 4.0f, 5.0f);
}
GodboltId:863b1z4GY
Book listing lst-0087-book.cpp:
// https://godbolt.org/z/863b1z4GY
int main() {
std::cout << std::setprecision(15) << std::fixed;
dreieck(100'000.0f, 99'999.999'79f, 0.000'29f);
dreieck(100'000.0, 99'999.999'79, 0.000'29);
}
Godbolt Listing lst-0087-godb.cpp, https://godbolt.org/z/863b1z4GY:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/863b1z4GY
int main() {
std::cout << std::setprecision(15) << std::fixed;
dreieck(100'000.0f, 99'999.999'79f, 0.000'29f);
dreieck(100'000.0, 99'999.999'79, 0.000'29);
}
Listing 4.45: Akkumulierte Zeitmessung
Book listing lst-0088-book.cpp:
// https://godbolt.org/z/drz7fzohh
#include <iostream>
#include <iomanip> // setprecision, fixed
constexpr int bilderProSek = 25;
constexpr int laufZeitInSek = 3600;
constexpr int bilderInsg = laufZeitInSek * bilderProSek;
constexpr float bildzeit = 1.0f / bilderProSek;
int main() {
float filmzeit = 0.f;
for(int n=1; n <= bilderInsg; ++n) { // 1 .. bilderInsg
filmzeit += bildzeit;// akkumulieren
// … hier Code für dieses Frame …
}
std::cout << std::setprecision(10) << std::fixed
<< filmzeit << '\n'; // Ausgabe: 3602.2695312500
}
Godbolt Listing lst-0088-godb.cpp, https://godbolt.org/z/drz7fzohh:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/drz7fzohh
#include <iostream>
#include <iomanip> // setprecision, fixed
constexpr int bilderProSek = 25;
constexpr int laufZeitInSek = 3600;
constexpr int bilderInsg = laufZeitInSek * bilderProSek;
constexpr float bildzeit = 1.0f / bilderProSek;
int main() {
float filmzeit = 0.f;
for(int n=1; n <= bilderInsg; ++n) { // 1 .. bilderInsg
filmzeit += bildzeit;// akkumulieren
// … hier Code für dieses Frame …
}
std::cout << std::setprecision(10) << std::fixed
<< filmzeit << '\n'; // Ausgabe: 3602.2695312500
}
Listing 4.46: Geschlossene Zeitberechnung
Book listing lst-0089-book.cpp:
// https://godbolt.org/z/xz6TGdc19
#include <iostream>
#include <iomanip> // setprecision, fixed
constexpr int bilderProSek = 25;
constexpr int laufZeitInSek = 3600;
constexpr int bilderInsg = laufZeitInSek * bilderProSek;
constexpr float bildzeit = 1.0f / bilderProSek;
int main() {
float filmzeit = 0.f;
for(int n=1; n <= bilderInsg; ++n) { // 1 .. bilderInsg, wegen Formel
filmzeit = bildzeit * n; // skalieren
// … hier Code für dieses Frame …
}
std::cout << std::setprecision(10) << std::fixed
<< filmzeit << '\n'; // Ausgabe: 3600.0000000000
}
Godbolt Listing lst-0089-godb.cpp, https://godbolt.org/z/xz6TGdc19:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/xz6TGdc19
#include <iostream>
#include <iomanip> // setprecision, fixed
constexpr int bilderProSek = 25;
constexpr int laufZeitInSek = 3600;
constexpr int bilderInsg = laufZeitInSek * bilderProSek;
constexpr float bildzeit = 1.0f / bilderProSek;
int main() {
float filmzeit = 0.f;
for(int n=1; n <= bilderInsg; ++n) { // 1 .. bilderInsg, wegen Formel
filmzeit = bildzeit * n; // skalieren
// … hier Code für dieses Frame …
}
std::cout << std::setprecision(10) << std::fixed
<< filmzeit << '\n'; // Ausgabe: 3600.0000000000
}
Listing 4.47: Mit komplexen Zahlen können Sie arithmetisch rechnen.
Book listing lst-0093-book.cpp:
// https://godbolt.org/z/43rYYeKx9
#include <iostream>
#include <iomanip> // setprecision, fixed
#include <complex>
using std::cout; using std::complex;
int main() {
using namespace std::complex_literals; // für i-Suffix
cout << std::fixed << std::setprecision(1);
complex<double> z1 = 1i * 1i; // i mal i
cout << z1 << '\n'; // Ausgabe: (–1.0,0.0)
complex<double> z2 = std::pow(1i, 2); // i-Quadrat
cout << z2 << '\n'; // Ausgabe: (–1.0,0.0)
double PI = std::acos(-1); // Länge eines halben Einheitskreises
complex<double> z3 = std::exp(1i * PI); // Euler-Formel
cout << z3 << '\n'; // Ausgabe: (–1.0,0.0)
complex<double> a(3, 4); // gewohnt als Konstruktor
complex<double> b = 1. - 2i; // praktisch als Literal
// Berechnungen:
cout << "a + b = " << a + b << "\n"; // Ausgabe: a + b = (4.0,2.0)
cout << "a * b = " << a * b << "\n"; // Ausgabe: a * b = (11.0,–2.0)
cout << "a / b = " << a / b << "\n"; // Ausgabe: a / b = (–1.0,2.0)
cout << "|a| = " << abs(a) << "\n"; // Ausgabe: |a| = 5.0
cout << "conj(a) = " << conj(a) << "\n"; // Ausgabe: conj(a) = (3.0,–4.0)
cout << "norm(a) = " << norm(a) << "\n"; // Ausgabe: norm(a) = 25.0
cout << "abs(a) = " << abs(a) << "\n"; // Ausgabe: abs(a) = 5.0
cout << "exp(a) = " << exp(a) << "\n"; // Ausgabe: exp(a) = (–13.1,–15.2)
}
Godbolt Listing lst-0093-godb.cpp, https://godbolt.org/z/43rYYeKx9:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/43rYYeKx9
#include <iostream>
#include <iomanip> // setprecision, fixed
#include <complex>
using std::cout; using std::complex;
int main() {
using namespace std::complex_literals; // für i-Suffix
cout << std::fixed << std::setprecision(1);
complex<double> z1 = 1i * 1i; // i mal i
cout << z1 << '\n'; // Ausgabe: (–1.0,0.0)
complex<double> z2 = std::pow(1i, 2); // i-Quadrat
cout << z2 << '\n'; // Ausgabe: (–1.0,0.0)
double PI = std::acos(-1); // Länge eines halben Einheitskreises
complex<double> z3 = std::exp(1i * PI); // Euler-Formel
cout << z3 << '\n'; // Ausgabe: (–1.0,0.0)
complex<double> a(3, 4); // gewohnt als Konstruktor
complex<double> b = 1. - 2i; // praktisch als Literal
// Berechnungen:
cout << "a + b = " << a + b << "\n"; // Ausgabe: a + b = (4.0,2.0)
cout << "a * b = " << a * b << "\n"; // Ausgabe: a * b = (11.0,–2.0)
cout << "a / b = " << a / b << "\n"; // Ausgabe: a / b = (–1.0,2.0)
cout << "|a| = " << abs(a) << "\n"; // Ausgabe: |a| = 5.0
cout << "conj(a) = " << conj(a) << "\n"; // Ausgabe: conj(a) = (3.0,–4.0)
cout << "norm(a) = " << norm(a) << "\n"; // Ausgabe: norm(a) = 25.0
cout << "abs(a) = " << abs(a) << "\n"; // Ausgabe: abs(a) = 5.0
cout << "exp(a) = " << exp(a) << "\n"; // Ausgabe: exp(a) = (–13.1,–15.2)
}
Listing 4.48: Ausgabe in unspezifizierter Reihenfolge
Book listing lst-0095-book.cpp:
// https://godbolt.org/z/eW1cfYcGs
#include <iostream>
void ausgabe(int a, int b) {
std::cout << a << ' ' << b << '\n';
}
int zahl() {
static int val = 0;
return ++val;
}
int main() {
ausgabe(zahl(), zahl()); // in welcher Reihenfolge?
}
Godbolt Listing lst-0095-godb.cpp, https://godbolt.org/z/eW1cfYcGs:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/eW1cfYcGs
#include <iostream>
void ausgabe(int a, int b) {
std::cout << a << ' ' << b << '\n';
}
int zahl() {
static int val = 0;
return ++val;
}
int main() {
ausgabe(zahl(), zahl()); // in welcher Reihenfolge?
}
Listing 5.1: Einrückung vier, Klammern in Zeile mit Schlüsselwort, wenige Leerzeichen
Book listing lst-0097-book.cpp:
// https://godbolt.org/z/eP77v498E
#include <iostream>
int func(int arg1, int arg2) {
if(arg1 > arg2) {
return arg1-arg2;
} else {
return arg2-arg1;
}
}
int main(int argc, const char* argv[]) {
for(int x=0; x<10; ++x) {
for(int y=0; y<10; ++y) {
std::cout << func(x,y) << " ";
}
std::cout << "\n";
}
}
Godbolt Listing lst-0097-godb.cpp, https://godbolt.org/z/eP77v498E:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/eP77v498E
#include <iostream>
int func(int arg1, int arg2) {
if(arg1 > arg2) {
return arg1-arg2;
} else {
return arg2-arg1;
}
}
int main(int argc, const char* argv[]) {
for(int x=0; x<10; ++x) {
for(int y=0; y<10; ++y) {
std::cout << func(x,y) << " ";
}
std::cout << "\n";
}
}
Listing 5.2: Einrückung zwei, Klammern nur wenn nötig und in eigener Zeile, mehr Leerzeichen
Book listing lst-0098-book.cpp:
// https://godbolt.org/z/4TMn37qhE
#include <iostream>
int func ( int arg1, int arg2 )
{
if (arg1 > arg2)
return arg1 - arg2;
else
return arg2 - arg1;
}
int main ( int argc, const char *argv[] )
{
for ( int x = 0 ; x < 10 ; ++x )
{
for ( int y = 0 ; y < 10 ; ++y )
std::cout << func ( x, y ) << " ";
std::cout << "\n";
}
}
Godbolt Listing lst-0098-godb.cpp, https://godbolt.org/z/4TMn37qhE:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/4TMn37qhE
#include <iostream>
int func ( int arg1, int arg2 )
{
if (arg1 > arg2)
return arg1 - arg2;
else
return arg2 - arg1;
}
int main ( int argc, const char *argv[] )
{
for ( int x = 0 ; x < 10 ; ++x )
{
for ( int y = 0 ; y < 10 ; ++y )
std::cout << func ( x, y ) << " ";
std::cout << "\n";
}
}
Listing 6.1: Einige Verwendungsmöglichkeiten von Strings
Book listing lst-0099-book.cpp:
// https://godbolt.org/z/vMvs47nfs
#include <iostream> // cin, cout für Eingabe und Ausgabe
#include <string> // Sie benötigen diesen Header der Standardbibliothek
void eingabe(
std::string &name, // als Parameter
unsigned &gebJahr)
{
/* Eingaben noch ohne gute Fehlerbehandlung... */
std::cout << "Name: ";
std::getline(std::cin, name); // getline liest in einen String ein
if(name.length() == 0) { // length ist eine Methode von string
std::cout << "Sie haben einen leeren Namen eingegeben.\n";
exit(1);
}
std::cout << "Geb.-Jahr: ";
std::cin >> gebJahr;
}
int main() {
/* Daten */
std::string name; // definiert und initialisiert eine string-Variable
unsigned gebJahr = 0;
/* Eingabe */
eingabe(name, gebJahr);
/* Berechnungen */
// …
}
Godbolt Listing lst-0099-godb.cpp, https://godbolt.org/z/vMvs47nfs:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/vMvs47nfs
#include <iostream> // cin, cout für Eingabe und Ausgabe
#include <string> // Sie benötigen diesen Header der Standardbibliothek
void eingabe(
std::string &name, // als Parameter
unsigned &gebJahr)
{
/* Eingaben noch ohne gute Fehlerbehandlung... */
std::cout << "Name: ";
std::getline(std::cin, name); // getline liest in einen String ein
if(name.length() == 0) { // length ist eine Methode von string
std::cout << "Sie haben einen leeren Namen eingegeben.\n";
exit(1);
}
std::cout << "Geb.-Jahr: ";
std::cin >> gebJahr;
}
int main() {
/* Daten */
std::string name; // definiert und initialisiert eine string-Variable
unsigned gebJahr = 0;
/* Eingabe */
eingabe(name, gebJahr);
/* Berechnungen */
// …
}
Listing 6.2: Eine string_view lässt sich aus einen string leicht erzeugen.
Book listing lst-0102-book.cpp:
// https://godbolt/.org/z/bdaE5nf5T
#include <iostream>
#include <string>
#include <string_view>
void zeige_mitte(std::string_view msg) { // string_view ist ein guter Parameter
auto mitte = msg.substr(2, msg.size()-4); // substr liefert string_view zurück
std::cout << mitte << "\n";
}
int main() {
using namespace std::literals;
const std::string aaa = "##Etwas Text##"s;
zeige_mitte(aaa); // Umwandlung in string_view
auto bbb = "++Mehr Text++"sv; // string_view als Literal
zeige_mitte(bbb);
}
Listing 6.3: Der Fehlerstream ist von der Standardausgabe getrennt.
Book listing lst-0103-book.cpp:
// https://godbolt/.org/z/raYaeY357
// Rufen Sie dieses Programm zum Beispiel mit 'prog.exe > datei.txt' auf.
#include <iostream> // cout, cerr
int main() {
std::cout << "Ausgabe nach cout\n"; // wird nach 'datei.txt' ausgegeben
std::cerr << "Fehlermeldung!\n"; // erscheint trotzdem auf der Konsole
std::cout << "Wieder normale Ausgabe\n"; // wieder in die Datei
}
Listing 6.4: Eine Funktion mit Ein- und Ausgabe
Book listing lst-0104-book.cpp:
// https://godbolt/.org/z/Gbe7aM4o4
#include <iostream> // cin, cout für Eingabe und Ausgabe
#include <string>
#include <array>
using std::cin; using std::cout; // Abkürzungen cin und cout
void eingabe(
std::string &name,
unsigned &gebTag,
unsigned &gebMonat,
unsigned &gebJahr,
long long &steuernummer,
std::array<int,12> &monatseinkommen) // array ist ein Container
{
/* Eingaben noch ohne gute Fehlerbehandlung… */
cout << "Name: ";
std::getline(cin, name); // getline nimmt Eingabestrom und String
if(name.length() == 0) {
cout << "Sie haben einen leeren Namen eingegeben.\n";
exit(1);
}
cout << "Geb.-Tag: "; cin >> gebTag;
cout << "Geb.-Monat: "; cin >> gebMonat;
cout << "Geb.-Jahr: "; cin >> gebJahr;
cout << "Steuernummer: "; cin >> steuernummer;
for(int m=0; m<12; ++m) {
cout << "Einkommen Monat " << m+1 << ": "; // mehrere Ausgaben
cin >> monatseinkommen[m]; // Einlesen mit Operator
}
cout << std::endl;
}
int main() {
std::string name{};
unsigned tag = 0;
unsigned monat = 0;
unsigned jahr = 0;
long long stNr = 0;
std::array<int,12> einkommen{};
eingabe(name, tag, monat, jahr, stNr, einkommen);
// … Berechnungen …
}
GodboltId:a6qqbWKMs
Book listing lst-0105-book.cpp:
//https://godbolt.org/z/a6qqbWKMs
#include <cstdlib>
#include <iostream>
int main(int argc, char* argv[]) {
for(int i=1; i<argc; ++i) { // Start bei 1
for(char* p=argv[i]; *p!='\0'; ++p) {
char c = toupper(*p);
std::cout << c;
}
std::cout << ' ';
}
std::cout << '\n';
}
Godbolt Listing lst-0105-godb.cpp, https://godbolt.org/z/a6qqbWKMs:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
//https://godbolt.org/z/a6qqbWKMs
#include <cstdlib>
#include <iostream>
int main(int argc, char* argv[]) {
for(int i=1; i<argc; ++i) { // Start bei 1
for(char* p=argv[i]; *p!='\0'; ++p) {
char c = toupper(*p);
std::cout << c;
}
std::cout << ' ';
}
std::cout << '\n';
}
GodboltId:McqfcWb8j
Book listing lst-0106-book.cpp:
//https://godbolt.org/z/McqfcWb8j
#include <fstream>
int main(int argc, char* argv[]) {
std::ofstream meineAusgabe{"output1.txt"};
meineAusgabe << "Zeile 1\n";
meineAusgabe << "Zeile 2\n";
}
Godbolt Listing lst-0106-godb.cpp, https://godbolt.org/z/McqfcWb8j:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
//https://godbolt.org/z/McqfcWb8j
#include <fstream>
int main(int argc, char* argv[]) {
std::ofstream meineAusgabe{"output1.txt"};
meineAusgabe << "Zeile 1\n";
meineAusgabe << "Zeile 2\n";
}
GodboltId:P9z8n8v16
Book listing lst-0107-book.cpp:
//https://godbolt.org/z/P9z8n8v16
#include <fstream>
int main(int argc, char* argv[]) {
int wert = 0;
std::ifstream meineEingabe{"input1.txt"};
meineEingabe >> wert;
}
Godbolt Listing lst-0107-godb.cpp, https://godbolt.org/z/P9z8n8v16:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
//https://godbolt.org/z/P9z8n8v16
#include <fstream>
int main(int argc, char* argv[]) {
int wert = 0;
std::ifstream meineEingabe{"input1.txt"};
meineEingabe >> wert;
}
Listing 6.5: Verwenden Sie den !-Operator, um den Zustand des Streams zu prüfen.
Book listing lst-0108-book.cpp:
//https://godbolt.org/z/ssW3eKEGq
#include <iostream> // cerr
#include <fstream>
int main(int argc, char* argv[]) {
int wert;
std::ifstream meineEingabe{"input1.txt"};
if(!meineEingabe) {
std::cerr << "Fehler beim Öffnen der Datei!\n";
} else {
meineEingabe >> wert;
}
}
Godbolt Listing lst-0108-godb.cpp, https://godbolt.org/z/ssW3eKEGq:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
//https://godbolt.org/z/ssW3eKEGq
#include <iostream> // cerr
#include <fstream>
int main(int argc, char* argv[]) {
int wert;
std::ifstream meineEingabe{"input1.txt"};
if(!meineEingabe) {
std::cerr << "Fehler beim Öffnen der Datei!\n";
} else {
meineEingabe >> wert;
}
}
Listing 6.6: Verwenden Sie Streammanipulatoren aus , um das Format der Ausgabe zu beeinflussen.
Book listing lst-0109-book.cpp:
//https://godbolt.org/z/EcnWz3r3j
#include <iostream>
#include <iomanip> // fixed, setprecision
#include <format> // C++20
using std::cout; using std::format; // Abkürzung cout, format
int main() {
cout << std::fixed // Punktschreibweise, nicht wissenschaftlich
<< std::setprecision(15); // 15 Nachkommastellen
cout << 0.5 << "\n"; // Ausgabe: 0.500000000000000*
cout << std::setprecision(5); // 5 Nachkommastellen
cout << 0.25 << "\n"; // Ausgabe: 0.25000
cout << format("{:0.4f}", 0.75) << "\n"; // (C++20) Ausgabe: 0.7500
return 0;
}
Godbolt Listing lst-0109-godb.cpp, https://godbolt.org/z/EcnWz3r3j:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
//https://godbolt.org/z/EcnWz3r3j
#include <iostream>
#include <iomanip> // fixed, setprecision
#include <format> // C++20
using std::cout; using std::format; // Abkürzung cout, format
int main() {
cout << std::fixed // Punktschreibweise, nicht wissenschaftlich
<< std::setprecision(15); // 15 Nachkommastellen
cout << 0.5 << "\n"; // Ausgabe: 0.500000000000000*
cout << std::setprecision(5); // 5 Nachkommastellen
cout << 0.25 << "\n"; // Ausgabe: 0.25000
cout << format("{:0.4f}", 0.75) << "\n"; // (C++20) Ausgabe: 0.7500
return 0;
}
Listing 6.7: In einem »array« speichern Sie eine feste Anzahl Elemente.
Book listing lst-0112-book.cpp:
// https://godbolt.org/z/cd1d1W7T1
#include <array>
#include <iostream>
using std::cout; using std::array; using std::string;
int main() {
array<string,7> wotag = { "Montag", "Dienstag", // definieren
"Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag" };
cout << "Die Woche beginnt mit " << wotag[0] << ".\n"; // Werte lesen
cout << "Sie endet mit " << wotag.at(6) << ".\n"; // sicheres Werte lesen
/* nordisch? */
wotag[5] = "Sonnabend"; // Werte verändern
}
Godbolt Listing lst-0112-godb.cpp, https://godbolt.org/z/cd1d1W7T1:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/cd1d1W7T1
#include <array>
#include <iostream>
using std::cout; using std::array; using std::string;
int main() {
array<string,7> wotag = { "Montag", "Dienstag", // definieren
"Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag" };
cout << "Die Woche beginnt mit " << wotag[0] << ".\n"; // Werte lesen
cout << "Sie endet mit " << wotag.at(6) << ".\n"; // sicheres Werte lesen
/* nordisch? */
wotag[5] = "Sonnabend"; // Werte verändern
}
Listing 6.8: Die Arraygröße muss konstant sein.
Book listing lst-0113-book.cpp:
// https://godbolt.org/z/zfe7dM4ex
#include <array>
#include <iostream>
constexpr size_t MONATE = 12; /* Monate im Jahr */
int main() {
std::array<unsigned,MONATE> mtage = { // okay mit einer Konstante
31,28,31,30,31,30,31,31,30,31,30,31};
unsigned alter = 0;
std::cout << "Wie alt sind Sie? "; std::cin >> alter;
std::array<int,alter> lebensjahre; // Arraygröße geht nicht per Variable
}
Godbolt Listing lst-0113-godb.cpp, https://godbolt.org/z/zfe7dM4ex:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/zfe7dM4ex
#include <array>
#include <iostream>
constexpr size_t MONATE = 12; /* Monate im Jahr */
int main() {
std::array<unsigned,MONATE> mtage = { // okay mit einer Konstante
31,28,31,30,31,30,31,31,30,31,30,31};
unsigned alter = 0;
std::cout << "Wie alt sind Sie? "; std::cin >> alter;
std::array<int,alter> lebensjahre; // Arraygröße geht nicht per Variable
}
Listing 6.9: Wenn Sie eine Arraydefinition mehrfach verwenden müssen, dann verwenden Sie »using«.
Book listing lst-0114-book.cpp:
// https://godbolt.org/z/a4zxbd99z
#include <array>
#include <algorithm> // accumulate
#include <numeric> // iota
using Januar = std::array<int,31>; // Alias für wiederholte Verwendung
void initJanuar(Januar& jan) { // das genaue Array als Parameter
std::iota(begin(jan), end(jan), 1); // füllt mit 1, 2, 3 … 31
}
int sumJanuar(const Januar& jan) { // das genaue Array als Parameter
return std::accumulate(begin(jan), end(jan), 0); // Hilfsfunktion für Summe
}
int main() {
Januar jan; // deklariert ein array<int,31>
initJanuar( jan );
int sum = sumJanuar( jan );
}
Godbolt Listing lst-0114-godb.cpp, https://godbolt.org/z/a4zxbd99z:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/a4zxbd99z
#include <array>
#include <algorithm> // accumulate
#include <numeric> // iota
using Januar = std::array<int,31>; // Alias für wiederholte Verwendung
void initJanuar(Januar& jan) { // das genaue Array als Parameter
std::iota(begin(jan), end(jan), 1); // füllt mit 1, 2, 3 … 31
}
int sumJanuar(const Januar& jan) { // das genaue Array als Parameter
return std::accumulate(begin(jan), end(jan), 0); // Hilfsfunktion für Summe
}
int main() {
Januar jan; // deklariert ein array<int,31>
initJanuar( jan );
int sum = sumJanuar( jan );
}
GodboltId:T9jsEoMj4
Book listing lst-0115-book.cpp:
// https://godbolt.org/z/T9jsEoMj4
#include <vector> // Sie benötigen diesen Header
int main() {
std::vector<int> quadrate{}; // leer initialisieren
for(int idx = 0; idx<100; ++idx) {
quadrate.push_back(idx*idx); // Anfügen eines Elements
}
}
Godbolt Listing lst-0115-godb.cpp, https://godbolt.org/z/T9jsEoMj4:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/T9jsEoMj4
#include <vector> // Sie benötigen diesen Header
int main() {
std::vector<int> quadrate{}; // leer initialisieren
for(int idx = 0; idx<100; ++idx) {
quadrate.push_back(idx*idx); // Anfügen eines Elements
}
}
Listing 6.10: Die einfachste Iteration benutzt eine bereichsbasierte »for«-Schleife.
Book listing lst-0116-book.cpp:
// https://godbolt.org/z/hhhavG5he
#include <vector>
#include <iostream> // cout, endl
int main() {
std::vector quadrate{1,4,9,16,25}; // gefüllt initialisieren
for(int zahl : quadrate) // zahl ist ein Quadrat nach dem anderen
std::cout << zahl << " ";
std::cout << std::endl;
}
Godbolt Listing lst-0116-godb.cpp, https://godbolt.org/z/hhhavG5he:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/hhhavG5he
#include <vector>
#include <iostream> // cout, endl
int main() {
std::vector quadrate{1,4,9,16,25}; // gefüllt initialisieren
for(int zahl : quadrate) // zahl ist ein Quadrat nach dem anderen
std::cout << zahl << " ";
std::cout << std::endl;
}
Listing 6.11: Der Zugriff auf die Elemente per Index
Book listing lst-0117-book.cpp:
// https://godbolt.org/z/xcKM7v1Eo
#include <vector>
#include <iostream> // cout, endl
int main() {
std::vector qus{1,4,9,16,25};
for(unsigned idx=0; idx<qus.size(); ++idx) // size enthält die Anzahl
std::cout << qus[idx] << " "; // [idx] oder at(idx) holt ein Element
std::cout << std::endl;
}
Godbolt Listing lst-0117-godb.cpp, https://godbolt.org/z/xcKM7v1Eo:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/xcKM7v1Eo
#include <vector>
#include <iostream> // cout, endl
int main() {
std::vector qus{1,4,9,16,25};
for(unsigned idx=0; idx<qus.size(); ++idx) // size enthält die Anzahl
std::cout << qus[idx] << " "; // [idx] oder at(idx) holt ein Element
std::cout << std::endl;
}
Listing 6.12: Der Einsatz von Iteratoren für eine Schleife
Book listing lst-0118-book.cpp:
// https://godbolt.org/z/1WG8zvhYe
#include <vector>
#include <iostream> // cout, endl
int main() {
std::vector qus{1,4,9,16,25};
for(auto it = qus.begin(); it!=qus.end(); ++it) // zwischen begin() und end()
std::cout << *it << " "; // mit *it kommen Sie vom Iterator zum Element
std::cout << std::endl;
}
Godbolt Listing lst-0118-godb.cpp, https://godbolt.org/z/1WG8zvhYe:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/1WG8zvhYe
#include <vector>
#include <iostream> // cout, endl
int main() {
std::vector qus{1,4,9,16,25};
for(auto it = qus.begin(); it!=qus.end(); ++it) // zwischen begin() und end()
std::cout << *it << " "; // mit *it kommen Sie vom Iterator zum Element
std::cout << std::endl;
}
Listing 6.13: Zählen mit einem Algorithmus
Book listing lst-0119-book.cpp:
// https://godbolt.org/z/4G67rso8T
#include <vector>
#include <algorithm> // count_if
#include <numeric> // iota
#include <iostream>
bool even(int n) { return n%2==0; } // Test auf gerade
int main() {
std::vector<int> data(100); // 100 x null
std::iota(data.begin(), data.end(), 0); // 0, 1, 2, … 99
// zählt gerade Zahlen
std::cout << std::count_if(data.begin(), data.end(), even);
}
Godbolt Listing lst-0119-godb.cpp, https://godbolt.org/z/4G67rso8T:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/4G67rso8T
#include <vector>
#include <algorithm> // count_if
#include <numeric> // iota
#include <iostream>
bool even(int n) { return n%2==0; } // Test auf gerade
int main() {
std::vector<int> data(100); // 100 x null
std::iota(data.begin(), data.end(), 0); // 0, 1, 2, … 99
// zählt gerade Zahlen
std::cout << std::count_if(data.begin(), data.end(), even);
}
Listing 7.1: Funktionen verwenden
Book listing lst-0127-book.cpp:
// https://godbolt.org/z/5ssc6W5o6
#include <iostream> // cout
#include <cmath> // sin
#include <string>
#include <vector>
using std::sin;
int main() {
std::cout << "sin(0.0): " << sin(0.0) << "\n"; // Aufruf von sin() mit Literal
double winkel = 3.1415/2;
std::cout << "sin("<<winkel<<"): "<<sin(winkel)<<"\n"; // Aufruf mit Variable
std::string name = "Han Solo";
std::cout << name.length() << "\n"; // Aufruf einer Methode
// … konzeptionell wie length(name)
std::vector<int> data{};
data.push_back(5); // weiterer Methodenaufruf mit Parameter
data.push_back(10);
std::cout << data.back() << " ";
data.pop_back();
std::cout << data.back() << "\n";
data.pop_back();
}
Godbolt Listing lst-0127-godb.cpp, https://godbolt.org/z/5ssc6W5o6:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/5ssc6W5o6
#include <iostream> // cout
#include <cmath> // sin
#include <string>
#include <vector>
using std::sin;
int main() {
std::cout << "sin(0.0): " << sin(0.0) << "\n"; // Aufruf von sin() mit Literal
double winkel = 3.1415/2;
std::cout << "sin("<<winkel<<"): "<<sin(winkel)<<"\n"; // Aufruf mit Variable
std::string name = "Han Solo";
std::cout << name.length() << "\n"; // Aufruf einer Methode
// … konzeptionell wie length(name)
std::vector<int> data{};
data.push_back(5); // weiterer Methodenaufruf mit Parameter
data.push_back(10);
std::cout << data.back() << " ";
data.pop_back();
std::cout << data.back() << "\n";
data.pop_back();
}
Listing 7.2: Verschiedene Rückgabetypen von Funktionen
Book listing lst-0128-book.cpp:
int func(); // liefert einen int zurück
std::string func(); // eine Zeichenkette aus der Standardbibliothek
void func(); // kein Rückgabewert
std::pair<int,std::string> func(); // zusammengesetzter Typ aus der Stdlib
vector<int> func(); // liefert einen neuen Container zurück
vector<int>& func(); // Verweis auf anderen Container
const vector<int>& func(); // ebenso, aber Sie können ihn nicht verändern
Listing 7.3: Parameter werden zunächst als Wert übergeben.
Book listing lst-0129-book.cpp:
// https://godbolt.org/z/8zcvMdM3b
#include <iostream>
void print_val8(int n) { // Parameter als Wert
std::cout << n << " ";
n = 8; // setzt Parameter auf 8
std::cout << n << "\n";
}
int main() {
int x = 5;
print_val8(x); // x als Wert: druckt 5, dann 8
std::cout << x << "\n"; // x ist unverändert 5
print_val8(42); // 42 als Wert: druckt 42, dann 8
}
Godbolt Listing lst-0129-godb.cpp, https://godbolt.org/z/8zcvMdM3b:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/8zcvMdM3b
#include <iostream>
void print_val8(int n) { // Parameter als Wert
std::cout << n << " ";
n = 8; // setzt Parameter auf 8
std::cout << n << "\n";
}
int main() {
int x = 5;
print_val8(x); // x als Wert: druckt 5, dann 8
std::cout << x << "\n"; // x ist unverändert 5
print_val8(42); // 42 als Wert: druckt 42, dann 8
}
Listing 7.4: Als Referenzparameter fügen Sie ein »&« hinzu.
Book listing lst-0130-book.cpp:
// https://godbolt.org/z/63dTshz3Y
#include <iostream>
void print_ref8(int& n) { // Parameter als Referenz
std::cout << n << " ";
n = 8; // setzt Parameter auf 8
std::cout << n << "\n";
}
int main() {
int x = 5;
print_ref8(x); // x als Referenz: druckt 5, dann 8
std::cout << x << "\n"; // x ist nun 8
}
Godbolt Listing lst-0130-godb.cpp, https://godbolt.org/z/63dTshz3Y:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/63dTshz3Y
#include <iostream>
void print_ref8(int& n) { // Parameter als Referenz
std::cout << n << " ";
n = 8; // setzt Parameter auf 8
std::cout << n << "\n";
}
int main() {
int x = 5;
print_ref8(x); // x als Referenz: druckt 5, dann 8
std::cout << x << "\n"; // x ist nun 8
}
Listing 7.5: Konstante Referenzen als Parameter können Sie für jeden Aufruf verwenden.
Book listing lst-0131-book.cpp:
// https://godbolt.org/z/dcKnx3Pno
#include <iostream>
void print_cref(const int& n) { // Parameter als konstante Referenz
std::cout << n << " ";
}
int main() {
int x = 5;
print_cref(x); // Aufruf mit einer Variablen
print_cref(42); // Aufruf mit einem konstanten Literal
}
Godbolt Listing lst-0131-godb.cpp, https://godbolt.org/z/dcKnx3Pno:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/dcKnx3Pno
#include <iostream>
void print_cref(const int& n) { // Parameter als konstante Referenz
std::cout << n << " ";
}
int main() {
int x = 5;
print_cref(x); // Aufruf mit einer Variablen
print_cref(42); // Aufruf mit einem konstanten Literal
}
GodboltId:fTvT5sKqY
Book listing lst-0133-book.cpp:
// https://godbolt.org/z/fTvT5sKqY
#include <iostream>
void verdopple(double &zahl) { // Ausgabeparameter als veränderbare Referenz
zahl *= 2.0;
}
int main() {
double zahl = 7.25;
verdopple(zahl);
std::cout << zahl << "\n"; // nun 14.5
}
Godbolt Listing lst-0133-godb.cpp, https://godbolt.org/z/fTvT5sKqY:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/fTvT5sKqY
#include <iostream>
void verdopple(double &zahl) { // Ausgabeparameter als veränderbare Referenz
zahl *= 2.0;
}
int main() {
double zahl = 7.25;
verdopple(zahl);
std::cout << zahl << "\n"; // nun 14.5
}
GodboltId:caExoc36Y
Book listing lst-0134-book.cpp:
// https://godbolt.org/z/caExoc36Y
#include <iostream>
double verdopple(double zahl) { // Wertparameter und Rückgabewert
return zahl * 2.0;
}
int main() {
double zahl = 7.25;
zahl = verdopple(zahl); // Änderung ausgedrückt durch Rückgabewert
std::cout << zahl << "\n"; // auch 14.5
}
Godbolt Listing lst-0134-godb.cpp, https://godbolt.org/z/caExoc36Y:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/caExoc36Y
#include <iostream>
double verdopple(double zahl) { // Wertparameter und Rückgabewert
return zahl * 2.0;
}
int main() {
double zahl = 7.25;
zahl = verdopple(zahl); // Änderung ausgedrückt durch Rückgabewert
std::cout << zahl << "\n"; // auch 14.5
}
Listing 7.6: Verschiedene Definitionen von Funktionen
Book listing lst-0135-book.cpp:
std::vector<int> prims = {2}; // globale Variable
bool testeObPrim(int n) { // eigene Funktion
for(int teil : prims) { // Zugriff auf globale Variable
if(teil*teil > n) // Zugriff auf Parameter
return true;
if(n%teil==0)
return false;
}
return true;
}
void berechnePrimsBis(int bis) { // noch eine eigene Funktion
for(int n=3; n<bis; n=n+2) {
if(testeObPrim(n)) { // eigene Funktion verwenden
prims.push_back(n);
}
}
}
Listing 7.7: Eine Vorwärtsdeklaration ohne Funktionskörper
Book listing lst-0136-book.cpp:
// … Auszug …
bool testeObPrim(int n); // Deklaration der später definierten Funktion
void berechnePrimsBis(int bis) {
for(int n=3; n<bis; n=n+2) {
if(testeObPrim(n)) { // Verwendung der später definierten Funktion
prims.push_back(n);
}
}
}
bool testeObPrim(int n) { // Definition erst nach der Verwendung
// … wie zuvor …
}
Listing 7.8: Hier finden einige Umwandlungen statt. Die Umwandlungen können auf Ihrem System anders aussehen.
Book listing lst-0138-book.cpp:
// https://godbolt.org/z/6hWvqhY7W
#include <iostream>
#include <format>
void prints(short s, int i, float f, double d) {
std::cout << std::format("short: {} int: {} float: {:.2f} double: {:.2f}\n",
s, i, f, d);
}
int main() {
int mill = 1000*1000; // 1 Million
prints(mill, mill, mill, mill); // short läuft über
// Ausgabe: short: 16960 int: 1000000 float: 1000000.00 double: 1000000.00
long bill = 1000L*1000L*1000L*1000L; // 1 Billion
prints(bill, bill, bill, bill); // sogar int läuft über, float wird ungenau
// Ausgabe: short: 4096 int: –727379968
// float: 999999995904.00 double: 1000000000000.00
float drei = 3.75f;
prints(drei, drei, drei, drei); // Nachkommastellen gehen verloren
// Ausgabe: short: 3 int: 3 float: 3.75 double: 3.75
}
Godbolt Listing lst-0138-godb.cpp, https://godbolt.org/z/6hWvqhY7W:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/6hWvqhY7W
#include <iostream>
#include <format>
void prints(short s, int i, float f, double d) {
std::cout << std::format("short: {} int: {} float: {:.2f} double: {:.2f}\n",
s, i, f, d);
}
int main() {
int mill = 1000*1000; // 1 Million
prints(mill, mill, mill, mill); // short läuft über
// Ausgabe: short: 16960 int: 1000000 float: 1000000.00 double: 1000000.00
long bill = 1000L*1000L*1000L*1000L; // 1 Billion
prints(bill, bill, bill, bill); // sogar int läuft über, float wird ungenau
// Ausgabe: short: 4096 int: –727379968
// float: 999999995904.00 double: 1000000000000.00
float drei = 3.75f;
prints(drei, drei, drei, drei); // Nachkommastellen gehen verloren
// Ausgabe: short: 3 int: 3 float: 3.75 double: 3.75
}
Listing 7.9: Die Funktionen »print« und »add« wurden für mehrere Typen überladen.
Book listing lst-0140-book.cpp:
// https://godbolt.org/z/9YcPraT15
#include <iostream>
void print(int wert) { std::cout << "int-Wert: " << wert << "\n"; }
void print(double wert) { std::cout << "double-Wert: " << wert << "\n"; }
void print(int w1, double w2) { std::cout << "Werte: "<<w1<<", "<<w2<<"\n"; }
int add(int n, int m) { return n + m; }
double add(double a, double b) { return a + b; }
int main() {
print( add(3, 4) ); // add(int, int) und print(int)
print( add(3.25f, 1.5f) ); // add(double, double) und print(double)
print( 7, 3.25 ); // print(int, double)
}
Godbolt Listing lst-0140-godb.cpp, https://godbolt.org/z/9YcPraT15:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/9YcPraT15
#include <iostream>
void print(int wert) { std::cout << "int-Wert: " << wert << "\n"; }
void print(double wert) { std::cout << "double-Wert: " << wert << "\n"; }
void print(int w1, double w2) { std::cout << "Werte: "<<w1<<", "<<w2<<"\n"; }
int add(int n, int m) { return n + m; }
double add(double a, double b) { return a + b; }
int main() {
print( add(3, 4) ); // add(int, int) und print(int)
print( add(3.25f, 1.5f) ); // add(double, double) und print(double)
print( 7, 3.25 ); // print(int, double)
}
GodboltId:58cTfvYhe
Book listing lst-0143-book.cpp:
// https://godbolt.org/z/58cTfvYhe
int zwei() { return 2; } // (ERR) einmal int als Rückgabetyp…
double zwei() { return 2.0; } // (ERR) … und einmal double
int main() {
int x = zwei();
double y = zwei();
}
Godbolt Listing lst-0143-godb.cpp, https://godbolt.org/z/58cTfvYhe:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/58cTfvYhe
int zwei() { return 2; } // (ERR) einmal int als Rückgabetyp…
double zwei() { return 2.0; } // (ERR) … und einmal double
int main() {
int x = zwei();
double y = zwei();
}
GodboltId:evGqG1oqa
Book listing lst-0144-book.cpp:
// https://godbolt.org/z/evGqG1oqa
int verdopple(int a) { return a * 2; }
double verdopple(double a) { return a * 2.0; }
int main() {
int x = verdopple(7);
double y = verdopple(7.0);
}
Godbolt Listing lst-0144-godb.cpp, https://godbolt.org/z/evGqG1oqa:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/evGqG1oqa
int verdopple(int a) { return a * 2; }
double verdopple(double a) { return a * 2.0; }
int main() {
int x = verdopple(7);
double y = verdopple(7.0);
}
Listing 7.10: Defaultparameter wirken wie mehrere Überladungen.
Book listing lst-0147-book.cpp:
// https://godbolt.org/z/fjc37rvEr
int add(int n=0, int m=0, int o=0, int p=0, int q=0) {
return n+m+o+p+q;
}
int main() {
std::cout << add(1,2,3,4,5) << "\n";
std::cout << add(1,2,3,4) << "\n"; // wie add(1,2,3,4,0)
std::cout << add(1,2,3) << "\n"; // wie add(1,2,3,0,0)
std::cout << add(1,2) << "\n"; // wie add(1,2,0,0,0)
std::cout << add(1) << "\n"; // wie add(1,0,0,0,0)
std::cout << add() << "\n"; // wie add(0,0,0,0,0)
}
Godbolt Listing lst-0147-godb.cpp, https://godbolt.org/z/fjc37rvEr:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/fjc37rvEr
int add(int n=0, int m=0, int o=0, int p=0, int q=0) {
return n+m+o+p+q;
}
int main() {
std::cout << add(1,2,3,4,5) << "\n";
std::cout << add(1,2,3,4) << "\n"; // wie add(1,2,3,4,0)
std::cout << add(1,2,3) << "\n"; // wie add(1,2,3,0,0)
std::cout << add(1,2) << "\n"; // wie add(1,2,0,0,0)
std::cout << add(1) << "\n"; // wie add(1,0,0,0,0)
std::cout << add() << "\n"; // wie add(0,0,0,0,0)
}
Listing 7.11: Alternative Syntax für Funktionsdeklarationen mit nachgestelltem Rückgabetyp
Book listing lst-0152-book.cpp:
auto func() -> int;
auto func() -> std::string;
auto func() -> void;
auto func() -> std::pair<int,std::string>;
auto func() -> vector<int>;
auto func() -> vector<int>&;
auto func() -> const vector<int>&;
Listing 7.12: Seit C++14 können Sie den Rückgabetyp durch den Compiler ermitteln lassen.
Book listing lst-0153-book.cpp:
// https://godbolt.org/z/6d5fxn9ed
auto maxOf2(int a, int b) {
return a<b ? b : a; // ein return: der Compiler ermittelt int
}
auto minOf3(int a, int b, int c) {
if(a<b) return a<c ? a : c;
else return b<c ? b : c;
}
auto medianOf3(int a, int b, int c) {
// komplexer, aber kein Problem für den Compiler
return minOf3(maxOf2(a,b), maxOf2(b,c), maxOf2(a,c));
}
Godbolt Listing lst-0153-godb.cpp, https://godbolt.org/z/6d5fxn9ed:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/6d5fxn9ed
auto maxOf2(int a, int b) {
return a<b ? b : a; // ein return: der Compiler ermittelt int
}
auto minOf3(int a, int b, int c) {
if(a<b) return a<c ? a : c;
else return b<c ? b : c;
}
auto medianOf3(int a, int b, int c) {
// komplexer, aber kein Problem für den Compiler
return minOf3(maxOf2(a,b), maxOf2(b,c), maxOf2(a,c));
}
GodboltId:dMvqG85fr
Book listing lst-0157-book.cpp:
// https://godbolt.org/z/dMvqG85fr
double add(double a, double b) { return a + b; }
double add(int, int) = delete; // add(3,4) verbieten
Godbolt Listing lst-0157-godb.cpp, https://godbolt.org/z/dMvqG85fr:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/dMvqG85fr
double add(double a, double b) { return a + b; }
double add(int, int) = delete; // add(3,4) verbieten
GodboltId:8Gdso36zf
Book listing lst-0158-book.cpp:
// https://godbolt.org/z/8Gdso36zf
class Widget : public Base {
explicit Widget(int); // keine automatische Konvertierung von int
~Widget(); // Destruktor mit ~ vor dem Namen
virtual void update(); // vorangestelltes virtual
void calc1() override; // nachgestelltes override
void calc2() final; // nachgestelltes final
void draw() const; // nachgestelltes const
virtual void paint() = 0; // abstrakte Methode
};
Godbolt Listing lst-0158-godb.cpp, https://godbolt.org/z/8Gdso36zf:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/8Gdso36zf
class Widget : public Base {
explicit Widget(int); // keine automatische Konvertierung von int
~Widget(); // Destruktor mit ~ vor dem Namen
virtual void update(); // vorangestelltes virtual
void calc1() override; // nachgestelltes override
void calc2() final; // nachgestelltes final
void draw() const; // nachgestelltes const
virtual void paint() = 0; // abstrakte Methode
};
Listing 8.1: Berechnet alle Primzahlen in einem von Benutzern bestimmten Bereich
Book listing lst-0159-book.cpp:
// https://godbolt.org/z/3hf7h67Pe
#include <iostream> // cout
#include <vector> // Container vector
#include <string> // stoi
int eingabeBis(int argc, const char* argv[]) {
/* Zahl ermitteln */
int bis = 0; // neue Variable einführen
if(argc<=1) { // if-Anweisung mit then- und else-Block
std::cout << "Bis wohin wollen Sie Primzahlen berechnen? ";
if(!(std::cin >> bis)) { // Prüfen des Rückgabewerts
return -1; // Fehler bei Benutzereingabe
}
} else { // else-Teil der if-Anweisung
bis = std::stoi(argv[1]);
}
return bis; // Eingabe zurückliefern
}
std::vector prims{2}; // neuer vector<int> mit Initialisierung
bool testeObPrim(int n) {
/* prims muss aufsteigend sortiert sein */
for(int teil : prims) { // bereichsbasierte for-Schleife
if(teil*teil > n) // zu groß, um überhaupt Teiler zu sein?
return true; // … dann innere Schleife vorzeitig beenden
if(n%teil==0) // ist Teiler?
return false; // … dann raus
}
return true; // kein Teiler gefunden
}
void berechnePrimsBis(int bis) {
/* Prims-Berechnung */
/* vector muss an dieser Stelle {2} enthalten */
for(int n=3; n<bis; n=n+2) { // Standard-for-Schleife
if(testeObPrim(n)) {
prims.push_back(n); // ist prim – merken als Teiler und Ergebnis
}
}
}
void ausgabePrims() {
for(int prim : prims) { // bereichsbasiert, über alle Elemente
std::cout << prim << " ";
}
std::cout << "\n";
}
int main(int argc, const char* argv[]) {
int bis = eingabeBis(argc, argv); // deklariert Variable
if(bis < 2) { return 1; } // Raus aus main mit Nicht-okay-Wert.
berechnePrimsBis(bis);
ausgabePrims();
return 0;
}
Godbolt Listing lst-0159-godb.cpp, https://godbolt.org/z/3hf7h67Pe:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/3hf7h67Pe
#include <iostream> // cout
#include <vector> // Container vector
#include <string> // stoi
int eingabeBis(int argc, const char* argv[]) {
/* Zahl ermitteln */
int bis = 0; // neue Variable einführen
if(argc<=1) { // if-Anweisung mit then- und else-Block
std::cout << "Bis wohin wollen Sie Primzahlen berechnen? ";
if(!(std::cin >> bis)) { // Prüfen des Rückgabewerts
return -1; // Fehler bei Benutzereingabe
}
} else { // else-Teil der if-Anweisung
bis = std::stoi(argv[1]);
}
return bis; // Eingabe zurückliefern
}
std::vector prims{2}; // neuer vector<int> mit Initialisierung
bool testeObPrim(int n) {
/* prims muss aufsteigend sortiert sein */
for(int teil : prims) { // bereichsbasierte for-Schleife
if(teil*teil > n) // zu groß, um überhaupt Teiler zu sein?
return true; // … dann innere Schleife vorzeitig beenden
if(n%teil==0) // ist Teiler?
return false; // … dann raus
}
return true; // kein Teiler gefunden
}
void berechnePrimsBis(int bis) {
/* Prims-Berechnung */
/* vector muss an dieser Stelle {2} enthalten */
for(int n=3; n<bis; n=n+2) { // Standard-for-Schleife
if(testeObPrim(n)) {
prims.push_back(n); // ist prim – merken als Teiler und Ergebnis
}
}
}
void ausgabePrims() {
for(int prim : prims) { // bereichsbasiert, über alle Elemente
std::cout << prim << " ";
}
std::cout << "\n";
}
int main(int argc, const char* argv[]) {
int bis = eingabeBis(argc, argv); // deklariert Variable
if(bis < 2) { return 1; } // Raus aus main mit Nicht-okay-Wert.
berechnePrimsBis(bis);
ausgabePrims();
return 0;
}
Listing 8.2: Dieses »for« bezieht sich auf nur eine Anweisung.
Book listing lst-0160-book.cpp:
for(int prim : prims) // for gefolgt von einer Anweisung
std::cout << prim << " ";
std::cout << "\n"; // nicht mehr Teil von for
Listing 8.3: Ein Anweisungsblock wird in { und } eingeschlossen.
Book listing lst-0161-book.cpp:
for(int prim : prims) { // Beginn des Blocks
std::cout << prim;
std::cout << " ";
} // Ende des Blocks
std::cout << "\n";
Listing 8.4: Wo Anweisungen erlaubt sind, können Sie auch einen Block erstellen.
Book listing lst-0162-book.cpp:
if(zahl > 50) { // äußerer Block
{ // 1. innerer Block
int ergebnis = zahl*zahl;
std::cout << "Quadrat: " << ergebnis << std::endl;
}
{ // 2. innerer Block
int ergebnis = zahl+zahl;
std::cout << "Verdoppelt: " << ergebnis << std::endl;
}
}
Listing 8.5: Zweimal »ergebnis« als neue Variable in einem Block geht nicht.
Book listing lst-0163-book.cpp:
if(zahl > 50) {
int ergebnis = zahl*zahl; // Definition von ergebnis
std::cout << "Quadrat: " << ergebnis << std::endl;
int ergebnis = zahl+zahl; // (ERR) Fehler: ergebnis wurde schon definiert
std::cout << "Verdoppelt: " << ergebnis << std::endl;
}
Listing 8.6: Sehr viele Variablen sind auch nicht gut.
Book listing lst-0164-book.cpp:
if(zahl > 50) {
int ergebnis1 = zahl*zahl; // ein Ergebnis
std::cout << "Quadrat: " << ergebnis << std::endl;
int ergebnis2 = zahl+zahl; // noch ein Ergebnis
std::cout << "Verdoppelt: " << ergebnis << std::endl;
int ergebnis3 = zahl+zahl+zahl; // und noch ein Ergebnis
// … viele Zeilen Code dazwischen …
// und hier?
// … noch mehr Programmzeilen …
}
Listing 8.7: Leere Anweisungen, wohin das Auge schaut
Book listing lst-0165-book.cpp:
int main() { ;;; // 3 leere Anweisungen
int zahl = 12 ; ; // 1 leere Anweisung
; int q = zahl*zahl ; // 1 leere Anweisung
if(q>50) {
q = q - 50;
} ; // 1 leere Anweisung
std::cout << q << std::endl;
}
Listing 8.8: Mit auto können Sie auch mehrere Variablen gleichzeitig initialisieren.
Book listing lst-0172-book.cpp:
// https://godbolt.org/z/G7P4ErTE1
#include <iostream>
#include <tuple> // make_tuple
auto mkTpl() {
return std::make_tuple(2, 'b', 3.14); // tuple<int,char,double>
}
struct Point {
int x, y;
};
int main() {
// Strukuriertes Binden eines C-Arrays
int ungerade[5] = { 1,3,7,9,11 };
auto [ eins, zwei, drei, vier, fuenf ] = ungerade;
// Strukuriertes Binden eines Tupels
auto [ two, bee, pi ] = mkTpl();
// Strukuriertes Binden einer Struktur
Point p0{ 10, 15 };
auto [ the_x, the_y ] = p0;
}
Godbolt Listing lst-0172-godb.cpp, https://godbolt.org/z/G7P4ErTE1:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/G7P4ErTE1
#include <iostream>
#include <tuple> // make_tuple
auto mkTpl() {
return std::make_tuple(2, 'b', 3.14); // tuple<int,char,double>
}
struct Point {
int x, y;
};
int main() {
// Strukuriertes Binden eines C-Arrays
int ungerade[5] = { 1,3,7,9,11 };
auto [ eins, zwei, drei, vier, fuenf ] = ungerade;
// Strukuriertes Binden eines Tupels
auto [ two, bee, pi ] = mkTpl();
// Strukuriertes Binden einer Struktur
Point p0{ 10, 15 };
auto [ the_x, the_y ] = p0;
}
GodboltId:YTTE96rfc
Book listing lst-0173-book.cpp:
// https://godbolt.org/z/YTTE96rfc
int main() {
int ungerade[5] = { 1,3,7,9,11 };
auto &[ eins, zwei, drei, vier, fuenf ] = ungerade;
auto &[ two, bee, pi ] = mkTpl(); // (ERR) kein &-Binden an Tempwerte
Point p0{ 10, 15 };
auto &[ the_x, the_y ] = p0;
}
Godbolt Listing lst-0173-godb.cpp, https://godbolt.org/z/YTTE96rfc:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/YTTE96rfc
int main() {
int ungerade[5] = { 1,3,7,9,11 };
auto &[ eins, zwei, drei, vier, fuenf ] = ungerade;
auto &[ two, bee, pi ] = mkTpl(); // (ERR) kein &-Binden an Tempwerte
Point p0{ 10, 15 };
auto &[ the_x, the_y ] = p0;
}
Listing 8.9: Dies sind alles Ausdrücke, die als Anweisung eingesetzt werden.
Book listing lst-0174-book.cpp:
bis = 99; // eine Zuweisung ist ein Ausdruck
bis = bis * 2 + 1; // Zuweisung mit einer Berechnung verbinden
berechnePrimsBis(bis); // ein Funktionsaufruf ist ein Ausdruck
std::cout << "Friedrich III"; // der Ausgabeoperator
Listing 8.10: Diese if-Anweisungen enthalten Initialisierer.
Book listing lst-0180-book.cpp:
// https://godbolt.org/z/d6PscKx4M
#include <map>
#include <string>
#include <algorithm> // any_of
#include <iostream> // cerr
std::map<int, std::string> m;
int main() {
if(auto it = m.find(10); it != m.end()) { return it->second.size(); }
if(char buf[10]={0}; std::fgets(buf, 10, stdin)) { m[0] += buf; }
std::string s;
if(auto keywords = {"if", "for", "while"};
std::any_of(keywords.begin(), keywords.end(),
[&s](const char* kw) { return s == kw; })) {
std::cerr << "Fehler\n";
}
}
Godbolt Listing lst-0180-godb.cpp, https://godbolt.org/z/d6PscKx4M:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/d6PscKx4M
#include <map>
#include <string>
#include <algorithm> // any_of
#include <iostream> // cerr
std::map<int, std::string> m;
int main() {
if(auto it = m.find(10); it != m.end()) { return it->second.size(); }
if(char buf[10]={0}; std::fgets(buf, 10, stdin)) { m[0] += buf; }
std::string s;
if(auto keywords = {"if", "for", "while"};
std::any_of(keywords.begin(), keywords.end(),
[&s](const char* kw) { return s == kw; })) {
std::cerr << "Fehler\n";
}
}
Listing 8.11: Der Compiler kann die Bedingung zur Compilezeit berechnen.
Book listing lst-0181-book.cpp:
// https://godbolt.org/z/Ycse4EWav
#include <iostream> // cout
template<typename T>
void speicher(T x) {
if constexpr(sizeof(T) > 4) {
std::cout << "Braucht viel Speicher: " << x << " \n";
}
}
constexpr auto DEBUG = true;
int main() {
if constexpr(DEBUG) {
std::cout << "Debug ist an.\n";
}
speicher<long long>(44LL);
}
Godbolt Listing lst-0181-godb.cpp, https://godbolt.org/z/Ycse4EWav:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Ycse4EWav
#include <iostream> // cout
template<typename T>
void speicher(T x) {
if constexpr(sizeof(T) > 4) {
std::cout << "Braucht viel Speicher: " << x << " \n";
}
}
constexpr auto DEBUG = true;
int main() {
if constexpr(DEBUG) {
std::cout << "Debug ist an.\n";
}
speicher<long long>(44LL);
}
Listing 8.12: Die Schleife wird 100-mal durchlaufen.
Book listing lst-0182-book.cpp:
// https://godbolt.org/z/Gc53z6K1W
#include <iostream>
int main() {
/* Summiere 1 bis 100 auf */
int summe = 0;
int zahl = 1;
while(zahl <= 100) // Bedingung
{ // Block, der wiederholt ausgeführt wird
summe += zahl; // fürs Ergebnis
zahl += 1; // nächste Zahl
} // Ende des wiederholten Blocks
std::cout << summe << std::endl;
}
Godbolt Listing lst-0182-godb.cpp, https://godbolt.org/z/Gc53z6K1W:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Gc53z6K1W
#include <iostream>
int main() {
/* Summiere 1 bis 100 auf */
int summe = 0;
int zahl = 1;
while(zahl <= 100) // Bedingung
{ // Block, der wiederholt ausgeführt wird
summe += zahl; // fürs Ergebnis
zahl += 1; // nächste Zahl
} // Ende des wiederholten Blocks
std::cout << summe << std::endl;
}
Listing 8.13: Der Rumpf einer »do-while«-Schleife wird mindestens einmal ausgeführt.
Book listing lst-0184-book.cpp:
// https://godbolt.org/z/6hh5KhExM
#include <iostream> // cin
#include <string>
int main() {
std::string line;
do { // mindestens einmal getline ausführen
std::getline(std::cin, line);
if(!std::cin) break; // Fehler oder Dateiende
} while(line != "quit"); // Ende bei bestimmter Eingabe
}
Godbolt Listing lst-0184-godb.cpp, https://godbolt.org/z/6hh5KhExM:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/6hh5KhExM
#include <iostream> // cin
#include <string>
int main() {
std::string line;
do { // mindestens einmal getline ausführen
std::getline(std::cin, line);
if(!std::cin) break; // Fehler oder Dateiende
} while(line != "quit"); // Ende bei bestimmter Eingabe
}
Listing 8.14: Summe mit einer »for«-Schleife
Book listing lst-0185-book.cpp:
// https://godbolt.org/z/7foYcMMaz
#include <iostream>
int main() {
/* Summiere 1 bis 100 auf */
int summe = 0;
for(int zahl=1; zahl <= 100; zahl+=1) { // kompakt
summe += zahl; // fürs Ergebnis
}
std::cout << summe << std::endl;
}
Godbolt Listing lst-0185-godb.cpp, https://godbolt.org/z/7foYcMMaz:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/7foYcMMaz
#include <iostream>
int main() {
/* Summiere 1 bis 100 auf */
int summe = 0;
for(int zahl=1; zahl <= 100; zahl+=1) { // kompakt
summe += zahl; // fürs Ergebnis
}
std::cout << summe << std::endl;
}
Listing 8.15: »for«-Schleife mit leerem Initialisierungsteil
Book listing lst-0186-book.cpp:
// https://godbolt.org/z/185ha3q3f
#include <iostream>
int main() {
/* Summiere 1 bis 100 auf */
int summe = 0;
int zahl = 1; // Initialisierung vor der Schleife
for( ; zahl <= 100; zahl=zahl+1) { // leere Initialisierung
summe = summe + zahl;
}
std::cout << zahl << std::endl; // zahl gibt es nun noch außerhalb
}
Godbolt Listing lst-0186-godb.cpp, https://godbolt.org/z/185ha3q3f:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/185ha3q3f
#include <iostream>
int main() {
/* Summiere 1 bis 100 auf */
int summe = 0;
int zahl = 1; // Initialisierung vor der Schleife
for( ; zahl <= 100; zahl=zahl+1) { // leere Initialisierung
summe = summe + zahl;
}
std::cout << zahl << std::endl; // zahl gibt es nun noch außerhalb
}
Listing 8.16: Schleifen ohne Bedingung müssen irgendwie anders beendet werden.
Book listing lst-0187-book.cpp:
int main() {
for( ; ; ) { // kein Init, keine Bedingung, kein Update – also für immer
/* ... Benutzereingabe */
/* ... falls Benutzer Quit wählt, Programmende */
/* ... ansonsten, Berechnung und Ausgabe */
}
}
Listing 8.17: Die bereichsbasierte »for«-Schleife erkennen Sie an dem Doppelpunkt.
Book listing lst-0188-book.cpp:
// Auszug
std::vector<int> prims{2}; // vector ist ein Container, bereit für Ranged For
void testeObPrim(int n) {
/* prims muss aufsteigend sortiert sein */
for(int teil : prims) { // bereichsbasierte for-Schleife
if(teil*teil > n)
return true;
if(n%teil==0)
return false;
}
return true;
}
// …
void ausgabePrims() {
for(int i=1; int prim : prims) { // bereichsbasierte for-Schleife
std::cout << i++ << ". Primzahl: " <<prim << " ";
}
std::cout << "\n";
}
// …
Listing 8.18: Jeder »case« deckt einen Fall ab, und nirgendwo wurde das »break« vergessen.
Book listing lst-0189-book.cpp:
// https://godbolt.org/z/5oe38obPr
#include <string>
#include <vector>
#include <iostream> // cout
void rechner(std::ostream& out, std::string input) {
std::vector<int> stapel {};
for(char c : input) {
if(c>='0' && c<='9') {
stapel.push_back( c-'0' ); // Zahlenwert des Zeichens
continue; // nächste Schleifeniteration
}
int top = 0;
int second = 0;
switch(c) { // Bedingung auf zeichen
case '+':
top = stapel.back(); stapel.pop_back();
second = stapel.back(); stapel.pop_back();
stapel.push_back(second + top);
break;
case '-':
top = stapel.back(); stapel.pop_back();
second = stapel.back(); stapel.pop_back();
stapel.push_back(second - top);
break;
case '*':
top = stapel.back(); stapel.pop_back();
second = stapel.back(); stapel.pop_back();
stapel.push_back(second * top);
break;
case '=':
for(int elem : stapel) { out << elem; }
out << "\n";
break;
case ' ':
break;
default:
out << "\n'" << c << "' verstehe ich nicht.\n";
} /* switch */
} /* for c */
}
int main(int argc, const char* argv[]) {
if(argc > 1) {
rechner(std::cout, argv[1]);
} else {
// 3 + 4 * 5 + 6 mit Punkt- vor Strichrechnung ergibt 29
rechner(std::cout, "345*+6+=");
}
}
Godbolt Listing lst-0189-godb.cpp, https://godbolt.org/z/5oe38obPr:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/5oe38obPr
#include <string>
#include <vector>
#include <iostream> // cout
void rechner(std::ostream& out, std::string input) {
std::vector<int> stapel {};
for(char c : input) {
if(c>='0' && c<='9') {
stapel.push_back( c-'0' ); // Zahlenwert des Zeichens
continue; // nächste Schleifeniteration
}
int top = 0;
int second = 0;
switch(c) { // Bedingung auf zeichen
case '+':
top = stapel.back(); stapel.pop_back();
second = stapel.back(); stapel.pop_back();
stapel.push_back(second + top);
break;
case '-':
top = stapel.back(); stapel.pop_back();
second = stapel.back(); stapel.pop_back();
stapel.push_back(second - top);
break;
case '*':
top = stapel.back(); stapel.pop_back();
second = stapel.back(); stapel.pop_back();
stapel.push_back(second * top);
break;
case '=':
for(int elem : stapel) { out << elem; }
out << "\n";
break;
case ' ':
break;
default:
out << "\n'" << c << "' verstehe ich nicht.\n";
} /* switch */
} /* for c */
}
int main(int argc, const char* argv[]) {
if(argc > 1) {
rechner(std::cout, argv[1]);
} else {
// 3 + 4 * 5 + 6 mit Punkt- vor Strichrechnung ergibt 29
rechner(std::cout, "345*+6+=");
}
}
Listing 8.19: Sehr selten gibt es »case«-Blöcke ohne »break«, noch seltener sinnvolle.
Book listing lst-0190-book.cpp:
// https://godbolt.org/z/jaMTcshEf
#include <iostream>
#include <string>
using std::string; using std::cout;
void rateMonat(unsigned welchenTagHabenwirHeute) {
switch(welchenTagHabenwirHeute) {
/* fehlende break-Anweisungen: Fall-through beabsichtigt */
default:
if(welchenTagHabenwirHeute>31) {
cout << "Sie schummeln";
break;
}
case 28:
case 29:
cout << "Feb ";
case 30:
cout << "Apr Jun Sep Nov ";
case 31:
cout << "Jan Mar Mai Jul Aug Okt Dez ";
}
cout << ".\n";
}
int main() {
rateMonat(31); // wenn wir heute den 31. hätten?
// Ausgabe: Jan Mar Mai Jul Aug Okt Dez .
rateMonat(30); // wenn es der 30. wäre?
// Ausgabe: Apr Jun Sep Nov Jan Mar Mai Jul Aug Okt Dez .
rateMonat(4);
// Ausgabe: Feb Apr Jun Sep Nov Jan Mar Mai Jul Aug Okt Dez .
rateMonat(77);
// Ausgabe: Sie schummeln.
}
Godbolt Listing lst-0190-godb.cpp, https://godbolt.org/z/jaMTcshEf:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/jaMTcshEf
#include <iostream>
#include <string>
using std::string; using std::cout;
void rateMonat(unsigned welchenTagHabenwirHeute) {
switch(welchenTagHabenwirHeute) {
/* fehlende break-Anweisungen: Fall-through beabsichtigt */
default:
if(welchenTagHabenwirHeute>31) {
cout << "Sie schummeln";
break;
}
case 28:
case 29:
cout << "Feb ";
case 30:
cout << "Apr Jun Sep Nov ";
case 31:
cout << "Jan Mar Mai Jul Aug Okt Dez ";
}
cout << ".\n";
}
int main() {
rateMonat(31); // wenn wir heute den 31. hätten?
// Ausgabe: Jan Mar Mai Jul Aug Okt Dez .
rateMonat(30); // wenn es der 30. wäre?
// Ausgabe: Apr Jun Sep Nov Jan Mar Mai Jul Aug Okt Dez .
rateMonat(4);
// Ausgabe: Feb Apr Jun Sep Nov Jan Mar Mai Jul Aug Okt Dez .
rateMonat(77);
// Ausgabe: Sie schummeln.
}
Listing 8.20: Mit break beenden Sie eine Schleife vorzeitig.
Book listing lst-0191-book.cpp:
// https://godbolt.org/z/75h9Y95vf
#include <iostream> // cout
int main() {
for(int x=1; x<20; x+=1) { // äußere for-Schleife
for(int y=1; y<20; y+=1) { // innere for-Schleife
int prod = x*y;
if(prod>=100) {
break; // raus aus innerer y-Schleife
}
std::cout << prod << " ";
} /* Ende for y */
// Ziel von break
} /* Ende for x */ // erste wirkliche Zeile nach break
std::cout << "\n";
}
Godbolt Listing lst-0191-godb.cpp, https://godbolt.org/z/75h9Y95vf:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/75h9Y95vf
#include <iostream> // cout
int main() {
for(int x=1; x<20; x+=1) { // äußere for-Schleife
for(int y=1; y<20; y+=1) { // innere for-Schleife
int prod = x*y;
if(prod>=100) {
break; // raus aus innerer y-Schleife
}
std::cout << prod << " ";
} /* Ende for y */
// Ziel von break
} /* Ende for x */ // erste wirkliche Zeile nach break
std::cout << "\n";
}
Listing 8.21: Mit »return« wird die aktuelle Funktion verlassen. Falls nötig, geben Sie einen Wert für die Rückgabe mit an.
Book listing lst-0192-book.cpp:
// https://godbolt.org/z/5ddxa9v1j
#include <iostream> // cout
int min3(int x, int y, int z) { // Funktion liefert einen int zurück
if(x<y) {
if(x<z) return x;
else return z;
} else if(y<z) {
return y;
}
else return z;
}
void printMin(int x, int y, int z) { // Funktion liefert nichts zurück
if(x<0 || y<0 || z<0) {
std::cout << "Bitte nur Zahlen groesser 0\n";
return;
}
std::cout << min3(x,y,z) << "\n";
} // hier steht kein return
int main() {
printMin(3, -4, 8);
printMin(6, 77, 4);
return; // besonderes return in main
}
Godbolt Listing lst-0192-godb.cpp, https://godbolt.org/z/5ddxa9v1j:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/5ddxa9v1j
#include <iostream> // cout
int min3(int x, int y, int z) { // Funktion liefert einen int zurück
if(x<y) {
if(x<z) return x;
else return z;
} else if(y<z) {
return y;
}
else return z;
}
void printMin(int x, int y, int z) { // Funktion liefert nichts zurück
if(x<0 || y<0 || z<0) {
std::cout << "Bitte nur Zahlen groesser 0\n";
return;
}
std::cout << min3(x,y,z) << "\n";
} // hier steht kein return
int main() {
printMin(3, -4, 8);
printMin(6, 77, 4);
return; // besonderes return in main
}
Listing 8.22: Vermeiden Sie goto-Anweisungen.
Book listing lst-0193-book.cpp:
// https://godbolt.org/z/ohd5Pr8fb
#include <iostream>
int main() {
int idx = 4;
goto mehr; // springe zu Label mehr
drucke: // Label für die nächste Anweisung
std::cout << idx << std::endl;
idx = idx * 2;
mehr:
idx = idx + 3;
if(idx < 20)
goto drucke; // goto kann auch in einem if stehen
ende: // dies ist ein Label, wird aber nicht verwendet
return 0;
}
Godbolt Listing lst-0193-godb.cpp, https://godbolt.org/z/ohd5Pr8fb:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/ohd5Pr8fb
#include <iostream>
int main() {
int idx = 4;
goto mehr; // springe zu Label mehr
drucke: // Label für die nächste Anweisung
std::cout << idx << std::endl;
idx = idx * 2;
mehr:
idx = idx + 3;
if(idx < 20)
goto drucke; // goto kann auch in einem if stehen
ende: // dies ist ein Label, wird aber nicht verwendet
return 0;
}
Listing 8.23: Eine Funktion weniger, aber ein Label und zwei »goto«-Anweisungen mehr.
Book listing lst-0194-book.cpp:
// https://godbolt.org/z/b361eeba3
// #includes, prims, eingabeBis(), ausgabePrims() und main() wie zuvor
std::vector<int> prims{2};
void berechnePrimsBis(int bis) {
/* Prims-Berechnung */
/* vector muss an dieser Stelle {2} enthalten */
for(int n=3; n<bis; n=n+2) {
for(int teil: prims) {
if(teil*teil > n)
goto prim; // mit goto, weil ein break …
if(n%teil==0)
goto nichtPrim;// … über zwei Schleifen nicht geht.
}
prim: ; // Ziel des Sprungs vor push_back
prims.push_back(n); // n ist prim! Merken als Teiler und Ergebnis
nichtPrim: ; // Ziel des Sprungs hinter push_back
}
}
Godbolt Listing lst-0194-godb.cpp, https://godbolt.org/z/b361eeba3:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/b361eeba3
// #includes, prims, eingabeBis(), ausgabePrims() und main() wie zuvor
std::vector<int> prims{2};
void berechnePrimsBis(int bis) {
/* Prims-Berechnung */
/* vector muss an dieser Stelle {2} enthalten */
for(int n=3; n<bis; n=n+2) {
for(int teil: prims) {
if(teil*teil > n)
goto prim; // mit goto, weil ein break …
if(n%teil==0)
goto nichtPrim;// … über zwei Schleifen nicht geht.
}
prim: ; // Ziel des Sprungs vor push_back
prims.push_back(n); // n ist prim! Merken als Teiler und Ergebnis
nichtPrim: ; // Ziel des Sprungs hinter push_back
}
}
Listing 8.24: Als Ausblick hier Ihre erste Exception-Behandlung mit »try« und »catch«
Book listing lst-0195-book.cpp:
// https://godbolt.org/z/cjfG7bc33
#include <iostream>
int main() {
try { // Beginn des try-Blocks
for(int n=1; ; n=n*2) {
if(n < 0) {
throw "Es gab einen Ueberlauf"; // Fehler auslösen
}
}
} // Ende des try-Blocks
catch(const char *fehler) { // falls dieser Fehler auftritt, …
std::cout << "Fehler: " << fehler << "\n"; // … behandle ihn so
}
}
Godbolt Listing lst-0195-godb.cpp, https://godbolt.org/z/cjfG7bc33:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/cjfG7bc33
#include <iostream>
int main() {
try { // Beginn des try-Blocks
for(int n=1; ; n=n*2) {
if(n < 0) {
throw "Es gab einen Ueberlauf"; // Fehler auslösen
}
}
} // Ende des try-Blocks
catch(const char *fehler) { // falls dieser Fehler auftritt, …
std::cout << "Fehler: " << fehler << "\n"; // … behandle ihn so
}
}
Listing 9.1: Typen von Ausdrücken sind wichtig, weil damit entschieden wird, wie es weitergeht.
Book listing lst-0196-book.cpp:
// https://godbolt.org/z/E1aGdox6q
#include <iostream> // cout
#include <string>
void drucke(int n) { // Funktion drucke für Typ int
std::cout << "Zahl:" << n << "\n";
}
void drucke(std::string s) { // gleicher Name, anderer Typ
std::cout << "Zeichenkette:" << s << "\n";
}
int main() {
int zahl = 10;
std::string name = "Bilbo";
drucke(zahl); // ruft drucke(int) auf, zahl ist int
drucke(name); // ruft drucke(string) auf, name ist string
drucke(11 + 22); // Ausdruck ist int
drucke(name + " Baggins"); // Ausdruck ist string
}
Godbolt Listing lst-0196-godb.cpp, https://godbolt.org/z/E1aGdox6q:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/E1aGdox6q
#include <iostream> // cout
#include <string>
void drucke(int n) { // Funktion drucke für Typ int
std::cout << "Zahl:" << n << "\n";
}
void drucke(std::string s) { // gleicher Name, anderer Typ
std::cout << "Zeichenkette:" << s << "\n";
}
int main() {
int zahl = 10;
std::string name = "Bilbo";
drucke(zahl); // ruft drucke(int) auf, zahl ist int
drucke(name); // ruft drucke(string) auf, name ist string
drucke(11 + 22); // Ausdruck ist int
drucke(name + " Baggins"); // Ausdruck ist string
}
GodboltId:EY5K6Wsr3
Book listing lst-0203-book.cpp:
// https://godbolt.org/z/EY5K6Wsr3
std::vector<int> data(10); // 10 mal 0 in einem vector
data.front() = 666; // schreibt 666 an die vorderste Stelle
Godbolt Listing lst-0203-godb.cpp, https://godbolt.org/z/EY5K6Wsr3:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/EY5K6Wsr3
std::vector<int> data(10); // 10 mal 0 in einem vector
data.front() = 666; // schreibt 666 an die vorderste Stelle
GodboltId:K9c913had
Book listing lst-0204-book.cpp:
// https://godbolt.org/z/K9c913had
if(int result; (result = read(buffer, 100)) != 0) {
std::cerr << "Es trat Fehler Nummer "<< result << " auf.\n";
}
Godbolt Listing lst-0204-godb.cpp, https://godbolt.org/z/K9c913had:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/K9c913had
if(int result; (result = read(buffer, 100)) != 0) {
std::cerr << "Es trat Fehler Nummer "<< result << " auf.\n";
}
Listing 10.1: Reagieren Sie auf viele Zustände mit Rückgabewerten unterschiedlicher Art.
Book listing lst-0210-book.cpp:
// https://godbolt.org/z/K37fMW8fE
#include <iostream> // cout, cerr
#include <fstream>
#include <vector>
#include <string>
using std::vector; using std::string; using std::cout; using std::cerr;
int zaehleWoerter(const string& filename) { // Rückgabe kleiner 0 bei Fehler
std::ifstream file{filename};
if(!file) { // Gab es einen Fehler beim Öffnen der Datei?
cerr << "Fehler beim Oeffnen von " << filename << "\n";
return -1; // dem Aufrufer einen Fehler mittels besonderem Wert melden
}
int count = 0;
string wort;
while(!file.eof()) { // noch nicht am Ende?
file >> wort;
++count;
}
return count-1; // –1: am EOF wurde noch ein Wort gelesen
}
bool process(const vector<string>& args) { // Rückgabe true bei alles okay
if(args.size() == 0) { // erwarten Parameter
cerr << "Kommandozeilenargument fehlt\n";
return false; // mittels Rückgabe einen Fehler mitteilen
} else {
bool result = true; // fürs Endergebnis
for(const string filename : args) {
cout << filename << ": ";
int count = zaehleWoerter(filename);
if(count < 0) { // besondere Rückgabe zeigt Fehler an
cout << "Fehler!\n";
result = false; // mindestens ein Fehler
} else {
cout << count << "\n"; // normales Ergebnis ausgeben
}
}
return result; // Gesamtergebnis zurückgeben
}
}
int main(int argc, const char* argv[]) {
bool result = process( // Rückgabewert enthält Fehlerindikator
{argv+1, argv+argc} ); // const char*[] nach vector<string>
if(result) { // Rückgabewert auswerten
return 0;
} else {
cerr << "Es trat ein Fehler auf.\n";
return 1; // außen Fehler anzeigen
}
}
Godbolt Listing lst-0210-godb.cpp, https://godbolt.org/z/K37fMW8fE:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/K37fMW8fE
#include <iostream> // cout, cerr
#include <fstream>
#include <vector>
#include <string>
using std::vector; using std::string; using std::cout; using std::cerr;
int zaehleWoerter(const string& filename) { // Rückgabe kleiner 0 bei Fehler
std::ifstream file{filename};
if(!file) { // Gab es einen Fehler beim Öffnen der Datei?
cerr << "Fehler beim Oeffnen von " << filename << "\n";
return -1; // dem Aufrufer einen Fehler mittels besonderem Wert melden
}
int count = 0;
string wort;
while(!file.eof()) { // noch nicht am Ende?
file >> wort;
++count;
}
return count-1; // –1: am EOF wurde noch ein Wort gelesen
}
bool process(const vector<string>& args) { // Rückgabe true bei alles okay
if(args.size() == 0) { // erwarten Parameter
cerr << "Kommandozeilenargument fehlt\n";
return false; // mittels Rückgabe einen Fehler mitteilen
} else {
bool result = true; // fürs Endergebnis
for(const string filename : args) {
cout << filename << ": ";
int count = zaehleWoerter(filename);
if(count < 0) { // besondere Rückgabe zeigt Fehler an
cout << "Fehler!\n";
result = false; // mindestens ein Fehler
} else {
cout << count << "\n"; // normales Ergebnis ausgeben
}
}
return result; // Gesamtergebnis zurückgeben
}
}
int main(int argc, const char* argv[]) {
bool result = process( // Rückgabewert enthält Fehlerindikator
{argv+1, argv+argc} ); // const char*[] nach vector<string>
if(result) { // Rückgabewert auswerten
return 0;
} else {
cerr << "Es trat ein Fehler auf.\n";
return 1; // außen Fehler anzeigen
}
}
Listing 10.2: Exceptions werden mit »throw« ausgelöst und mit »try-catch« behandelt.
Book listing lst-0211-book.cpp:
// https://godbolt.org/z/sz9hxKozf
#include <iostream> // cout, cerr
#include <vector>
#include <string>
#include <fstream> // ifstream
#include <stdexcept> // invalid_argument
using std::vector; using std::string; using std::cout; using std::ifstream;
size_t zaehleWoerter(const string& filename) { // 0 oder größer
std::ifstream file{}; // ungeöffnet erzeugen
// anmelden für Exceptions:
file.exceptions(ifstream::failbit | ifstream::badbit);
file.open(filename); // könnte eine Exception auslösen
size_t count = 0;
string wort;
file.exceptions(ifstream::badbit); // EOF keine Exception mehr
while(!file.eof()) { // noch nicht am Ende?
file >> wort; ++count;
}
return count-1; // –1: am EOF wurde noch ein Wort gelesen
}
void process(const vector<string>& args) {
if(args.size() == 0) { // process erwartet Parameter
throw std::invalid_argument{"Kommandozeilenarg. fehlt"}; // auslösen
} else {
for(const string filename : args) {
cout << filename << ": " << zaehleWoerter(filename) << std::endl;
}
}
}
int main(int argc, const char* argv[]) {
try { // Block mit Fehlerbehandlungen
process(
vector<string>{argv+1, argv+argc} ); // const char*[] nach vector<string>
return 0;
} catch(std::exception &exc) { // Fehlerbehandlung
std::cerr << "Es trat ein Fehler auf: " << exc.what() << "\n";
return 1;
}
}
Godbolt Listing lst-0211-godb.cpp, https://godbolt.org/z/sz9hxKozf:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/sz9hxKozf
#include <iostream> // cout, cerr
#include <vector>
#include <string>
#include <fstream> // ifstream
#include <stdexcept> // invalid_argument
using std::vector; using std::string; using std::cout; using std::ifstream;
size_t zaehleWoerter(const string& filename) { // 0 oder größer
std::ifstream file{}; // ungeöffnet erzeugen
// anmelden für Exceptions:
file.exceptions(ifstream::failbit | ifstream::badbit);
file.open(filename); // könnte eine Exception auslösen
size_t count = 0;
string wort;
file.exceptions(ifstream::badbit); // EOF keine Exception mehr
while(!file.eof()) { // noch nicht am Ende?
file >> wort; ++count;
}
return count-1; // –1: am EOF wurde noch ein Wort gelesen
}
void process(const vector<string>& args) {
if(args.size() == 0) { // process erwartet Parameter
throw std::invalid_argument{"Kommandozeilenarg. fehlt"}; // auslösen
} else {
for(const string filename : args) {
cout << filename << ": " << zaehleWoerter(filename) << std::endl;
}
}
}
int main(int argc, const char* argv[]) {
try { // Block mit Fehlerbehandlungen
process(
vector<string>{argv+1, argv+argc} ); // const char*[] nach vector<string>
return 0;
} catch(std::exception &exc) { // Fehlerbehandlung
std::cerr << "Es trat ein Fehler auf: " << exc.what() << "\n";
return 1;
}
}
Listing 10.3: Ein »catch« kann auch innerhalb einer Schleife stehen.
Book listing lst-0212-book.cpp:
void process(const vector<string>& args) {
if(args.size() == 0) { // erwarte Parameter
throw std::invalid_argument{"Kommandozeilenargument fehlt"};
} else {
for(const string filename : args) {
cout << filename << ": ";
try {
cout << zaehleWoerter(filename) << "\n";
} catch(std::exception &exc) {
cout << "Fehler: " << exc.what() << "\n";
}
}
}
}
Listing 10.4: Mit »throw« ohne Parameter werfen Sie die gerade behandelte Ausnahme weiter.
Book listing lst-0213-book.cpp:
try {
cout << zaehleWoerter(filename) << "\n";
} catch(std::exception &exc) {
cout << "Fehler: " << exc.what() << "\n";
throw; // weiterwerfen
}
Listing 10.5: Sie können auch andere Typen als Ausnahme auslösen.
Book listing lst-0215-book.cpp:
// https://godbolt.org/z/67cd5bhhE
#include <string>
#include <iostream> // cout
using std::string; using std::to_string; using std::cout;
void fehlerAusloesen(int fehlerfall) {
try {
if(fehlerfall < 10) throw (int)fehlerfall;
else if(fehlerfall < 20) throw 1.0/(fehlerfall-10.0);
else throw string{"Fehler " + to_string(fehlerfall)};
} catch(int eval) {
cout << "int-fehler: " << eval << "\n";
} catch(double eval) {
cout << "double-fehler: " << eval << "\n";
} catch(string eval) {
cout << "string-fehler: " << eval << "\n";
}
}
int main() {
fehlerAusloesen(3); // int-fehler: 3
fehlerAusloesen(14); // Ausgabe: double-fehler: 0.25
fehlerAusloesen(50); // Ausgabe: string-fehler: Fehler 50
}
Godbolt Listing lst-0215-godb.cpp, https://godbolt.org/z/67cd5bhhE:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/67cd5bhhE
#include <string>
#include <iostream> // cout
using std::string; using std::to_string; using std::cout;
void fehlerAusloesen(int fehlerfall) {
try {
if(fehlerfall < 10) throw (int)fehlerfall;
else if(fehlerfall < 20) throw 1.0/(fehlerfall-10.0);
else throw string{"Fehler " + to_string(fehlerfall)};
} catch(int eval) {
cout << "int-fehler: " << eval << "\n";
} catch(double eval) {
cout << "double-fehler: " << eval << "\n";
} catch(string eval) {
cout << "string-fehler: " << eval << "\n";
}
}
int main() {
fehlerAusloesen(3); // int-fehler: 3
fehlerAusloesen(14); // Ausgabe: double-fehler: 0.25
fehlerAusloesen(50); // Ausgabe: string-fehler: Fehler 50
}
Listing 10.6: Lassen Sie sich wenigstens den Fehlertyp und -text ausgeben, anstatt Ihr Programm aus »main« herauspurzeln zu lassen.
Book listing lst-0216-book.cpp:
// https://godbolt.org/z/TsP33njar
#include <iostream>
#include <stdexcept> // exception
int main() {
try {
// … Ihr sonstiger Code …
} catch(std::exception& exc) {
std::cerr << "main: " << exc.what() << "\n";
}
}
Godbolt Listing lst-0216-godb.cpp, https://godbolt.org/z/TsP33njar:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/TsP33njar
#include <iostream>
#include <stdexcept> // exception
int main() {
try {
// … Ihr sonstiger Code …
} catch(std::exception& exc) {
std::cerr << "main: " << exc.what() << "\n";
}
}
Listing 11.1: Die Haupt-Headerdatei der Bibliothek qwort.hpp
Book listing lst-0217-book.cpp:
// https://godbolt.org/z/7nasGjGq6
#ifndef QWORT_H // Header-Guard
#define QWORT_H
#include <string>
#include <memory> // unique_ptr
namespace qw { // Namensraum der Bibliothek
int version();
namespace impl_multimap {
class index_impl;
}
class index {
using index_impl = impl_multimap::index_impl;
public:
index();
~index() noexcept; // wird für pimpl benötigt
index(const index&) = default;
index(index&&) noexcept;
index& operator=(const index&) = default;
index& operator=(index&&) = default;
public:
void add(const std::string &arg);
size_t size() const;
std::string getBestMatch(const std::string& query) const;
public: // public für Tests
std::string normalize(std::string arg) const;
private:
const std::unique_ptr<index_impl> pimpl;
};
} // namespace qw
#endif // Header-Guard
Godbolt Listing lst-0217-godb.cpp, https://godbolt.org/z/7nasGjGq6:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/7nasGjGq6
#ifndef QWORT_H // Header-Guard
#define QWORT_H
#include <string>
#include <memory> // unique_ptr
namespace qw { // Namensraum der Bibliothek
int version();
namespace impl_multimap {
class index_impl;
}
class index {
using index_impl = impl_multimap::index_impl;
public:
index();
~index() noexcept; // wird für pimpl benötigt
index(const index&) = default;
index(index&&) noexcept;
index& operator=(const index&) = default;
index& operator=(index&&) = default;
public:
void add(const std::string &arg);
size_t size() const;
std::string getBestMatch(const std::string& query) const;
public: // public für Tests
std::string normalize(std::string arg) const;
private:
const std::unique_ptr<index_impl> pimpl;
};
} // namespace qw
#endif // Header-Guard
Listing 11.2: Die Schnittstellenklasse leitet alle Aufrufe an die Implementierungsklasse weiter.
Book listing lst-0218-book.cpp:
// https://godbolt.org/z/zbcdd1jha
#include "qwort/qwort.hpp" // selbst
#include <map>
#include <algorithm> // transform
#include <cctype> // toupper
#include "impl_multimap.hpp"
using std::map; using std::string;
namespace qw {
int version() {
return 1;
}
// Verwaltung
index::index()
: pimpl{ new index_impl{} }
{ }
index::~index() noexcept = default;
index::index(index&&) noexcept = default;
// Schnittstelle
void index::add(const string &arg) {
pimpl->add(normalize(arg), arg);
}
size_t index::size() const {
return pimpl->size();
}
string index::getBestMatch(const string& query) const {
return pimpl->getBestMatch(normalize(query));
}
string index::normalize(string str) const {
using namespace std; // begin, end
transform(begin(str), end(str), begin(str), [](char c) {
return ::isalpha(c) ? ::toupper(c) : '#';
});
return str;
}
} // namespace qw
Godbolt Listing lst-0218-godb.cpp, https://godbolt.org/z/zbcdd1jha:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/zbcdd1jha
#include "qwort/qwort.hpp" // selbst
#include <map>
#include <algorithm> // transform
#include <cctype> // toupper
#include "impl_multimap.hpp"
using std::map; using std::string;
namespace qw {
int version() {
return 1;
}
// Verwaltung
index::index()
: pimpl{ new index_impl{} }
{ }
index::~index() noexcept = default;
index::index(index&&) noexcept = default;
// Schnittstelle
void index::add(const string &arg) {
pimpl->add(normalize(arg), arg);
}
size_t index::size() const {
return pimpl->size();
}
string index::getBestMatch(const string& query) const {
return pimpl->getBestMatch(normalize(query));
}
string index::normalize(string str) const {
using namespace std; // begin, end
transform(begin(str), end(str), begin(str), [](char c) {
return ::isalpha(c) ? ::toupper(c) : '#';
});
return str;
}
} // namespace qw
Listing 11.3: Header der Implementierungsklasse
Book listing lst-0219-book.cpp:
// https://godbolt.org/z/5Tfr6xxa5
#include <string>
#include <string_view>
#include <vector>
#include <map> // multimap
namespace qw::impl_multimap {
using std::vector; using std::multimap;
using std::string; using std::string_view;
class index_impl {
vector<string> entries;
multimap<string,size_t> qindex;
public:
void add(string_view normalized, string_view original);
string getBestMatch(string_view normalized) const;
size_t size() const {
return entries.size();
}
private:
vector<string> qgramify(string_view normalized) const;
static constexpr size_t Q = 3;
static const std::string PREFIX;
static const std::string SUFFIX;
public: // test interface
vector<string> _qgramify(string_view n) const { return qgramify(n); }
static size_t _q() { return Q; }
static std::string _prefix() { return PREFIX; }
static std::string _suffix() { return SUFFIX; }
};
} // namespace qw::impl_multimap
Godbolt Listing lst-0219-godb.cpp, https://godbolt.org/z/5Tfr6xxa5:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/5Tfr6xxa5
#include <string>
#include <string_view>
#include <vector>
#include <map> // multimap
namespace qw::impl_multimap {
using std::vector; using std::multimap;
using std::string; using std::string_view;
class index_impl {
vector<string> entries;
multimap<string,size_t> qindex;
public:
void add(string_view normalized, string_view original);
string getBestMatch(string_view normalized) const;
size_t size() const {
return entries.size();
}
private:
vector<string> qgramify(string_view normalized) const;
static constexpr size_t Q = 3;
static const std::string PREFIX;
static const std::string SUFFIX;
public: // test interface
vector<string> _qgramify(string_view n) const { return qgramify(n); }
static size_t _q() { return Q; }
static std::string _prefix() { return PREFIX; }
static std::string _suffix() { return SUFFIX; }
};
} // namespace qw::impl_multimap
Listing 11.4: Der Header der Implementierungsklasse
Book listing lst-0220-book.cpp:
// https://godbolt.org/z/41sPszG1G
#include "impl_multimap.hpp" // Header zu dieser Datei
#include <map>
#include <string>
#include <string_view>
namespace qw::impl_multimap {
using std::vector; using std::multimap; using std::map; using std::string;
using std::string_view; using namespace std::literals::string_literals;
void index_impl::add(string_view normalized, string_view original) {
/* TODO: Vorhandensein in 'entries' prüfen */
const auto pos = entries.size(); // Index des neuen Eintrags
entries.push_back(string(original));
auto qgrams = qgramify(normalized);
for(const auto& qgram : qgrams) {
qindex.insert( make_pair(qgram, pos) );
}
}
string index_impl::getBestMatch(string_view normalized) const {
auto qgrams = qgramify(normalized);
/* hits speichert, welche Wörter wie oft getroffen wurden */
map<size_t, size_t> hits; /* 'entries-index' zu 'hit-count' */
size_t maxhits = 0z; /* immer: max(hits.second) */
for(const auto& qgram : qgrams) {
auto [beg, end] = qindex.equal_range(qgram);
for(auto it=beg; it!=end; ++it) {
hits[it->second] += 1z; /* hit-count des Eintrags */
if(hits[it->second] > maxhits) { /* max-Suche einfacher */
maxhits = hits[it->second];
}
}
}
/* Suche ersten Eintrag mit maxhits. Bessere Implementierung mit PrioQueue möglich */
for(auto const &hit : hits) {
if(hit.second == maxhits) {
return entries[hit.first];
}
}
/* nur erreicht, wenn entries leer ist */
return ""s;
}
const string index_impl::PREFIX = string(Q-1, '^');
const string index_impl::SUFFIX = string(Q-1, '$');
vector<string> index_impl::qgramify(string_view normalized) const {
auto word = PREFIX + string(normalized)+SUFFIX; /* Trick für bessere QGramme */
vector<string> result {};
auto left = word.cbegin();
auto right = std::next(word.cbegin(), Q); /* okay: |"^^"|+|"$$"| => 3 */
for( ; right <= word.end(); ++left, ++right) {
result.emplace_back(left, right);
}
return result;
}
} // namespace qw::impl_multimap
Godbolt Listing lst-0220-godb.cpp, https://godbolt.org/z/41sPszG1G:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/41sPszG1G
#include "impl_multimap.hpp" // Header zu dieser Datei
#include <map>
#include <string>
#include <string_view>
namespace qw::impl_multimap {
using std::vector; using std::multimap; using std::map; using std::string;
using std::string_view; using namespace std::literals::string_literals;
void index_impl::add(string_view normalized, string_view original) {
/* TODO: Vorhandensein in 'entries' prüfen */
const auto pos = entries.size(); // Index des neuen Eintrags
entries.push_back(string(original));
auto qgrams = qgramify(normalized);
for(const auto& qgram : qgrams) {
qindex.insert( make_pair(qgram, pos) );
}
}
string index_impl::getBestMatch(string_view normalized) const {
auto qgrams = qgramify(normalized);
/* hits speichert, welche Wörter wie oft getroffen wurden */
map<size_t, size_t> hits; /* 'entries-index' zu 'hit-count' */
size_t maxhits = 0z; /* immer: max(hits.second) */
for(const auto& qgram : qgrams) {
auto [beg, end] = qindex.equal_range(qgram);
for(auto it=beg; it!=end; ++it) {
hits[it->second] += 1z; /* hit-count des Eintrags */
if(hits[it->second] > maxhits) { /* max-Suche einfacher */
maxhits = hits[it->second];
}
}
}
/* Suche ersten Eintrag mit maxhits. Bessere Implementierung mit PrioQueue möglich */
for(auto const &hit : hits) {
if(hit.second == maxhits) {
return entries[hit.first];
}
}
/* nur erreicht, wenn entries leer ist */
return ""s;
}
const string index_impl::PREFIX = string(Q-1, '^');
const string index_impl::SUFFIX = string(Q-1, '$');
vector<string> index_impl::qgramify(string_view normalized) const {
auto word = PREFIX + string(normalized)+SUFFIX; /* Trick für bessere QGramme */
vector<string> result {};
auto left = word.cbegin();
auto right = std::next(word.cbegin(), Q); /* okay: |"^^"|+|"$$"| => 3 */
for( ; right <= word.end(); ++left, ++right) {
result.emplace_back(left, right);
}
return result;
}
} // namespace qw::impl_multimap
Listing 11.5: So ziemlich das einfachste Beispielprogramm der Bibliothek
Book listing lst-0221-book.cpp:
// https://godbolt.org/z/Gvcj6hhYf
#include <cstdlib> // EXIT_SUCCESS
#include <iostream> // cout
#include <vector>
#include <string>
#include "qwort/qwort.hpp"
using std::cout; using std::vector; using std::string;
int main(int argc, const char* argv[]) {
cout << "qwort version " << qw::version() << "\n";
/* Index bauen */
qw::index myindex{};
/* - Demodaten */
myindex.add("Deutschland");
myindex.add("Griechenland");
/* Abfragen erzeugen */
vector<string> args(argv+1, argv+argc); // iteratorbasierte Initialisierung
for(auto &querystring : args) {
cout << "Suche '" << querystring << "'... ";
const auto match = myindex.getBestMatch(querystring);
cout << match << "\n";
}
return EXIT_SUCCESS;
}
Godbolt Listing lst-0221-godb.cpp, https://godbolt.org/z/Gvcj6hhYf:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Gvcj6hhYf
#include <cstdlib> // EXIT_SUCCESS
#include <iostream> // cout
#include <vector>
#include <string>
#include "qwort/qwort.hpp"
using std::cout; using std::vector; using std::string;
int main(int argc, const char* argv[]) {
cout << "qwort version " << qw::version() << "\n";
/* Index bauen */
qw::index myindex{};
/* - Demodaten */
myindex.add("Deutschland");
myindex.add("Griechenland");
/* Abfragen erzeugen */
vector<string> args(argv+1, argv+argc); // iteratorbasierte Initialisierung
for(auto &querystring : args) {
cout << "Suche '" << querystring << "'... ";
const auto match = myindex.getBestMatch(querystring);
cout << match << "\n";
}
return EXIT_SUCCESS;
}
Listing 12.1: Listing 12.1 Einen eigenen Datentyp erzeugen Sie mit »struct«.
Book listing lst-0222-book.cpp:
// https://godbolt.org/z/8YqoTEx58
#include <string>
#include <iostream> // cout
#include <format>
using std::string; using std::cout; using std::format;
struct Person { // definiert den neuen Typ Person
string name_;
int alter_;
string ort_;
}; // abschließendes Semikolon
void drucke(Person p) { // ganze Person als ein Parameter
cout << format("{} ({}) aus {}\n",
p.name_, p.alter_, p.ort_); // Zugriff per Punkt
}
int main() {
Person otto {"Otto", 45, "Kassel" }; // Initialisierung
drucke(otto); // Aufruf als Einheit
}
Godbolt Listing lst-0222-godb.cpp, https://godbolt.org/z/8YqoTEx58:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/8YqoTEx58
#include <string>
#include <iostream> // cout
#include <format>
using std::string; using std::cout; using std::format;
struct Person { // definiert den neuen Typ Person
string name_;
int alter_;
string ort_;
}; // abschließendes Semikolon
void drucke(Person p) { // ganze Person als ein Parameter
cout << format("{} ({}) aus {}\n",
p.name_, p.alter_, p.ort_); // Zugriff per Punkt
}
int main() {
Person otto {"Otto", 45, "Kassel" }; // Initialisierung
drucke(otto); // Aufruf als Einheit
}
Listing 12.2: Listing 12.2 Die Deklaration einer Klasse nennt erst mal nur ihren Namen, die Definition enthält alle ihre Elemente.
Book listing lst-0223-book.cpp:
// https://godbolt.org/z/jPqn7c3T8
#include <memory> // shared_ptr
#include <vector> // vector
struct Mitarbeiter; // Klassendeklaration
struct Chef; // Klassendeklaration
struct Mitarbeiter { // Klassendefinition
std::shared_ptr<Chef> chef_; // Zeiger auf Chef
void print() const; // Methodendeklaration
};
struct Chef { // Definition
std::vector<std::shared_ptr<Mitarbeiter>> mitarbeiter_; // Zeiger auf Mitarbeiter
void print() const; // Methodendeklaration
};
void Mitarbeiter::print() const { // Methodendefinition
// …
}
void Chef::print() const { // Methodendefinition
// …
}
Godbolt Listing lst-0223-godb.cpp, https://godbolt.org/z/jPqn7c3T8:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/jPqn7c3T8
#include <memory> // shared_ptr
#include <vector> // vector
struct Mitarbeiter; // Klassendeklaration
struct Chef; // Klassendeklaration
struct Mitarbeiter { // Klassendefinition
std::shared_ptr<Chef> chef_; // Zeiger auf Chef
void print() const; // Methodendeklaration
};
struct Chef { // Definition
std::vector<std::shared_ptr<Mitarbeiter>> mitarbeiter_; // Zeiger auf Mitarbeiter
void print() const; // Methodendeklaration
};
void Mitarbeiter::print() const { // Methodendefinition
// …
}
void Chef::print() const { // Methodendefinition
// …
}
Listing 12.3: Listing 12.3 Mit designierten Initialisierern geben Sie die zu setzenden Elemente an.
Book listing lst-0226-book.cpp:
// https://godbolt.org/z/e9Wshbx3q
Person otto1 {"Otto", 45, "Kassel" }; // korrekt
Person otto2 {"Kassel", 45, "Otto" }; // oje, vertauscht, und keiner merkt's
Person hans { .name_ = "Hans", .alter_ = 23, .ort_ = "Berlin" }; // okay
Person willi { .name_ = "Willi", .alter_ = 48 }; // okay, nicht alle angegeben
Person karl { "Karl", .alter_ = 53 }; // (ERR) alle designiert oder keiner
Person paul { .alter_ = 34, .name_ = "Paul", .ort = "Bonn" }; // (ERR) vertauscht
Person pit(.name_="Pit", .alter_=34, .ort_="Wyk"); // (ERR) nicht mit runden Klammern
Godbolt Listing lst-0226-godb.cpp, https://godbolt.org/z/e9Wshbx3q:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/e9Wshbx3q
Person otto1 {"Otto", 45, "Kassel" }; // korrekt
Person otto2 {"Kassel", 45, "Otto" }; // oje, vertauscht, und keiner merkt's
Person hans { .name_ = "Hans", .alter_ = 23, .ort_ = "Berlin" }; // okay
Person willi { .name_ = "Willi", .alter_ = 48 }; // okay, nicht alle angegeben
Person karl { "Karl", .alter_ = 53 }; // (ERR) alle designiert oder keiner
Person paul { .alter_ = 34, .name_ = "Paul", .ort = "Bonn" }; // (ERR) vertauscht
Person pit(.name_="Pit", .alter_=34, .ort_="Wyk"); // (ERR) nicht mit runden Klammern
GodboltId:xnT7voqen
Book listing lst-0227-book.cpp:
// https://godbolt.org/z/xnT7voqen
// Ausschnitt
Person erzeuge(string name, int alter, string ort) { // Rückgabetyp
Person result {name, alter, ort};
return result;
}
int main() {
Person otto = erzeuge("Otto", 45, "Kassel"); // Rückgabe speichern
drucke(otto);
}
Godbolt Listing lst-0227-godb.cpp, https://godbolt.org/z/xnT7voqen:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/xnT7voqen
// Ausschnitt
Person erzeuge(string name, int alter, string ort) { // Rückgabetyp
Person result {name, alter, ort};
return result;
}
int main() {
Person otto = erzeuge("Otto", 45, "Kassel"); // Rückgabe speichern
drucke(otto);
}
GodboltId:YYfxMdfP8
Book listing lst-0228-book.cpp:
// https://godbolt.org/z/YYfxMdfP8
Person erzeuge(string name, int alter, string ort) {
return Person{name, alter, ort}; // direkt zurückgegeben
}
int main() {
drucke(erzeuge("Otto", 45, "Kassel")); // Rückgabe direkt verwendet
}
Godbolt Listing lst-0228-godb.cpp, https://godbolt.org/z/YYfxMdfP8:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/YYfxMdfP8
Person erzeuge(string name, int alter, string ort) {
return Person{name, alter, ort}; // direkt zurückgegeben
}
int main() {
drucke(erzeuge("Otto", 45, "Kassel")); // Rückgabe direkt verwendet
}
Listing 12.4: Listing 12.4 Hier ist die Angabe von Person beim return nötig.
Book listing lst-0231-book.cpp:
// https://godbolt.org/z/KvTx3rPs5
auto erzeuge(string name, int alter, string ort) {
return Person{name, alter, ort}; // auto verlangt Konstruktornamen
}
auto erzeuge2(string name, int alter, string ort) {
return {name, alter, ort}; // (ERR) auto mit initializer_list geht nicht
}
Godbolt Listing lst-0231-godb.cpp, https://godbolt.org/z/KvTx3rPs5:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/KvTx3rPs5
auto erzeuge(string name, int alter, string ort) {
return Person{name, alter, ort}; // auto verlangt Konstruktornamen
}
auto erzeuge2(string name, int alter, string ort) {
return {name, alter, ort}; // (ERR) auto mit initializer_list geht nicht
}
Listing 12.5: Listing 12.5 Methoden packen Daten und Verhalten zusammen.
Book listing lst-0232-book.cpp:
// https://godbolt.org/z/M1ozTorEz
#include <string>
#include <iostream>
#include <format>
using std::string; using std::cout; using std::format;
struct Person {
string name_;
int alter_;
string ort_;
void drucke(); // Funktion als Methode des Typs
};
void Person::drucke() { // Name der Methode wird um Person:: erweitert
cout << format("{} ({}) aus {}\n",
name_, alter_, ort_); // in einer Methode können Sie direkt auf Felder zugreifen
}
int main() {
Person otto {"Otto", 45, "Kassel" };
otto.drucke(); // Aufruf der Methode für eine Variable des Typs
}
Godbolt Listing lst-0232-godb.cpp, https://godbolt.org/z/M1ozTorEz:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/M1ozTorEz
#include <string>
#include <iostream>
#include <format>
using std::string; using std::cout; using std::format;
struct Person {
string name_;
int alter_;
string ort_;
void drucke(); // Funktion als Methode des Typs
};
void Person::drucke() { // Name der Methode wird um Person:: erweitert
cout << format("{} ({}) aus {}\n",
name_, alter_, ort_); // in einer Methode können Sie direkt auf Felder zugreifen
}
int main() {
Person otto {"Otto", 45, "Kassel" };
otto.drucke(); // Aufruf der Methode für eine Variable des Typs
}
Listing 12.6: Listing 12.6 Die Methode »gruss()« verwendet Felder — mittels »this« ist es immer das zum aufgerufenen Objekt gehörende Feld.
Book listing lst-0233-book.cpp:
struct Person {
//… Rest wie zuvor …
string gruss();
};
string Person::gruss() {
return format("Hallo {} aus {}", this->name_, this->ort_);
}
int main() {
Person anna { "Anna", 33, "Hof" };
Person nina { "Nina", 22, "Wyk" };
anna.gruss();
nina.gruss();
}
Listing 12.7: Listing 12.7 So trennen Sie Methoden und Daten voneinander.
Book listing lst-0235-book.cpp:
string gruss(Person * const p) { // impliziter Parameter explizit gemacht
return format("Hallo {} aus {}", p->name_, p->ort_);
}
GodboltId:hEvqWqqc6
Book listing lst-0236-book.cpp:
// https://godbolt.org/z/hEvqWqqc6
int wert = 5; // globale Variable
struct Wrap {
int wert = 3; // Datenfeld
void setze(int wert) { // Parameter
this->wert = wert + ::wert;
}
};
Godbolt Listing lst-0236-godb.cpp, https://godbolt.org/z/hEvqWqqc6:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/hEvqWqqc6
int wert = 5; // globale Variable
struct Wrap {
int wert = 3; // Datenfeld
void setze(int wert) { // Parameter
this->wert = wert + ::wert;
}
};
Listing 12.8: Listing 12.8 »drucke« nimmt einen Stream als Argument.
Book listing lst-0239-book.cpp:
// https://godbolt.org/z/bjWKjaeaK
// Ausschnitt. Person wie zuvor
void Person::drucke(std::ostream& os) {
os << format("{} ({}) aus {}", name_, alter_, ort_);
}
int main() {
Person karl {"Karl", 12, "Stetten"};
karl.drucke(cout); // auf dem Bildschirm
cout << "\n";
std::ofstream datei {"personen.txt"};
karl.drucke(datei); // in eine Datei
// automatischer Test:
std::ostringstream oss{}; // schreibt in einen string
karl.drucke(oss);
if(oss.str() == "Karl (12) aus Stetten") {
cout << "ok\n";
} else {
cout << "Fehler in Person::drucke!\n";
return 1; // Fehler nach außen weiterleiten
}
}
Godbolt Listing lst-0239-godb.cpp, https://godbolt.org/z/bjWKjaeaK:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/bjWKjaeaK
// Ausschnitt. Person wie zuvor
void Person::drucke(std::ostream& os) {
os << format("{} ({}) aus {}", name_, alter_, ort_);
}
int main() {
Person karl {"Karl", 12, "Stetten"};
karl.drucke(cout); // auf dem Bildschirm
cout << "\n";
std::ofstream datei {"personen.txt"};
karl.drucke(datei); // in eine Datei
// automatischer Test:
std::ostringstream oss{}; // schreibt in einen string
karl.drucke(oss);
if(oss.str() == "Karl (12) aus Stetten") {
cout << "ok\n";
} else {
cout << "Fehler in Person::drucke!\n";
return 1; // Fehler nach außen weiterleiten
}
}
Listing 12.9: Listing 12.9 Sie können den Standardoperator für die Ausgabe überladen.
Book listing lst-0240-book.cpp:
std::ostream& Person::drucke(std::ostream& os) {
return os << format("{} ({}) aus {}", name_, alter_, ort_);
}
std::ostream& operator<<(std::ostream& os, Person p) {
return p.drucke(os);
}
Listing 12.10: Listing 12.10 Die Ausgabe mit << erreichen Sie durch Überladung einer freien Funktion.
Book listing lst-0242-book.cpp:
// https://godbolt.org/z/bEdfWqqnn
// Ausschnitt …
std::ostream& drucke(std::ostream& os);
};
std::ostream& Person::drucke(std::ostream& os) {
return os << format("{} ({}) aus {}", p.name_, p.alter_, p.ort_);
}
std::ostream& operator<<(std::ostream& os, Person p) {
return p.drucke(os);
}
int main() {
Person paul {"Paul", 23, "Dresden"};
cout << "Sie sind " << paul << ", richtig?\n";
}
Godbolt Listing lst-0242-godb.cpp, https://godbolt.org/z/bEdfWqqnn:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/bEdfWqqnn
// Ausschnitt …
std::ostream& drucke(std::ostream& os);
};
std::ostream& Person::drucke(std::ostream& os) {
return os << format("{} ({}) aus {}", p.name_, p.alter_, p.ort_);
}
std::ostream& operator<<(std::ostream& os, Person p) {
return p.drucke(os);
}
int main() {
Person paul {"Paul", 23, "Dresden"};
cout << "Sie sind " << paul << ", richtig?\n";
}
Listing 12.11: Listing 12.11 Methoden können auch inline definiert werden.
Book listing lst-0243-book.cpp:
// https://godbolt.org/z/zf9Tc4ahs
#include <string>
#include <iostream> // ostream
using std::string; using std::ostream;
struct Person {
string name_;
int alter_;
string ort_;
ostream& drucke(ostream& os) { // Methode inline definiert
return os << format("{} ({}) aus {}", p.name_, p.alter_, p.ort_);
}
};
Godbolt Listing lst-0243-godb.cpp, https://godbolt.org/z/zf9Tc4ahs:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/zf9Tc4ahs
#include <string>
#include <iostream> // ostream
using std::string; using std::ostream;
struct Person {
string name_;
int alter_;
string ort_;
ostream& drucke(ostream& os) { // Methode inline definiert
return os << format("{} ({}) aus {}", p.name_, p.alter_, p.ort_);
}
};
Listing 12.12: Listing 12.12 So definieren Sie einen Konstruktor.
Book listing lst-0248-book.cpp:
struct Person {
string name_;
int alter_;
string ort_;
Person(); // Konstruktor deklarieren
};
Person::Person()
: name_{"kein Name"} // Initialisierungswert für name_
, alter_{-1} // Initialisierungswert für alter_
, ort_{"kein Ort"} // Initialisierungswert für ort_
{ } // leerer Funktionskörper
Listing 12.13: Listing 12.13 Auch mehrere Konstruktoren sind möglich.
Book listing lst-0250-book.cpp:
// https://godbolt.org/z/cqoTsWbhW
#include <string>
#include <string_view>
using std::string; using sview = std::string_view;
struct Person {
string name_;
int alter_;
string ort_;
Person(); // Konstruktor ohne Argumente
Person(sview n, int a, sview o); // Konstruktor mit drei Argumenten
Person(sview n, int a); // Konstruktor mit zwei Argumenten
Person(sview n); // Konstruktor mit einem Argument
};
Person::Person()
: name_{"kein Name"}, alter_{-1}, ort_{"kein Ort"} { }
Person::Person(sview n, int a, sview o)
: name_{n}, alter_{a}, ort_{o} { }
Person::Person(sview n, int a)
: name_{n}, alter_{a}, ort_{"kein Ort"} { }
Person::Person(sview n)
: name_{n}, alter_{-1}, ort_{"kein Ort"} { }
Godbolt Listing lst-0250-godb.cpp, https://godbolt.org/z/cqoTsWbhW:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/cqoTsWbhW
#include <string>
#include <string_view>
using std::string; using sview = std::string_view;
struct Person {
string name_;
int alter_;
string ort_;
Person(); // Konstruktor ohne Argumente
Person(sview n, int a, sview o); // Konstruktor mit drei Argumenten
Person(sview n, int a); // Konstruktor mit zwei Argumenten
Person(sview n); // Konstruktor mit einem Argument
};
Person::Person()
: name_{"kein Name"}, alter_{-1}, ort_{"kein Ort"} { }
Person::Person(sview n, int a, sview o)
: name_{n}, alter_{a}, ort_{o} { }
Person::Person(sview n, int a)
: name_{n}, alter_{a}, ort_{"kein Ort"} { }
Person::Person(sview n)
: name_{n}, alter_{-1}, ort_{"kein Ort"} { }
Listing 12.14: Listing 12.14 Membervariablen können mit Defaultwerten ausgestattet werden.
Book listing lst-0251-book.cpp:
// https://godbolt.org/z/vzneMWW9r
#include <string>
#include <string_view>
using std::string; using sview = std::string_view;
struct Person {
string name_ = "kein Name";
int alter_ = -1;
string ort_ = "kein Ort";
Person() {}
Person(sview n, int a, sview o)
: name_{n}, alter_{a}, ort_{o} { }
Person(sview n, int a)
: name_{n}, alter_{a} { }
Person(sview n)
: name_{n} { }
};
Godbolt Listing lst-0251-godb.cpp, https://godbolt.org/z/vzneMWW9r:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/vzneMWW9r
#include <string>
#include <string_view>
using std::string; using sview = std::string_view;
struct Person {
string name_ = "kein Name";
int alter_ = -1;
string ort_ = "kein Ort";
Person() {}
Person(sview n, int a, sview o)
: name_{n}, alter_{a}, ort_{o} { }
Person(sview n, int a)
: name_{n}, alter_{a} { }
Person(sview n)
: name_{n} { }
};
Listing 12.15: Listing 12.15 Ein Konstruktor kann einen Teil der Initialisierung an einen anderen Konstruktor weiterreichen.
Book listing lst-0252-book.cpp:
// https://godbolt.org/z/83efx7Gex
#include <string>
#include <string_view>
using std::string; using sview = std::string_view;
struct Person {
string name_;
int alter_;
string ort_;
Person(sview n, int a, sview o) // delegierter Konstruktor
: name_(n), alter_(a), ort_(o) { } // … ausimplementiert
Person() : Person{"kein Name",-1,"kein Ort"} { } // delegierend
Person(sview n, int a) : Person{n, a, "kein Ort"} { } // delegierend
Person(sview n) : Person{n, -1, "kein Ort"} { } // delegierend
};
Godbolt Listing lst-0252-godb.cpp, https://godbolt.org/z/83efx7Gex:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/83efx7Gex
#include <string>
#include <string_view>
using std::string; using sview = std::string_view;
struct Person {
string name_;
int alter_;
string ort_;
Person(sview n, int a, sview o) // delegierter Konstruktor
: name_(n), alter_(a), ort_(o) { } // … ausimplementiert
Person() : Person{"kein Name",-1,"kein Ort"} { } // delegierend
Person(sview n, int a) : Person{n, a, "kein Ort"} { } // delegierend
Person(sview n) : Person{n, -1, "kein Ort"} { } // delegierend
};
Listing 12.16: Listing 12.16 Auch ein Konstruktor kann mit Defaultparametern überladen werden.
Book listing lst-0253-book.cpp:
// https://godbolt.org/z/Exh4PnMTE
#include <string>
#include <string_view>
using std::string; using sview = std::string_view;
struct Person {
string name_;
int alter_;
string ort_;
Person(sview n = "N.N.", int a = 18, sview o = "Berlin")
: name_(n), alter_(a), ort_(o) { }
};
Godbolt Listing lst-0253-godb.cpp, https://godbolt.org/z/Exh4PnMTE:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Exh4PnMTE
#include <string>
#include <string_view>
using std::string; using sview = std::string_view;
struct Person {
string name_;
int alter_;
string ort_;
Person(sview n = "N.N.", int a = 18, sview o = "Berlin")
: name_(n), alter_(a), ort_(o) { }
};
Listing 12.17: Listing 12.17 Ein Konstruktor mit allen vorbesetzten Argumenten wird zum Defaultkonstruktor.
Book listing lst-0255-book.cpp:
// https://godbolt.org/z/vb1Wsr5d3
#include <vector>
#include <string>
#include <string_view>
#include <iostream>
using std::string; using std::cout; using sview = std::string_view;
struct Person {
string name_;
int alter_;
string ort_;
// fungiert als Defaultkonstruktor:
Person(sview n = "N.N.", int a = 18, sview o = "Berlin")
: name_(n), alter_(a), ort_(o) { }
};
int main() {
std::vector<Person> personen{}; // zunächst leer
personen.resize(5); // auf fünf »leere« Personen erweitern
cout << personen[3].ort_ << "\n"; // Ausgabe: Berlin
}
Godbolt Listing lst-0255-godb.cpp, https://godbolt.org/z/vb1Wsr5d3:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/vb1Wsr5d3
#include <vector>
#include <string>
#include <string_view>
#include <iostream>
using std::string; using std::cout; using sview = std::string_view;
struct Person {
string name_;
int alter_;
string ort_;
// fungiert als Defaultkonstruktor:
Person(sview n = "N.N.", int a = 18, sview o = "Berlin")
: name_(n), alter_(a), ort_(o) { }
};
int main() {
std::vector<Person> personen{}; // zunächst leer
personen.resize(5); // auf fünf »leere« Personen erweitern
cout << personen[3].ort_ << "\n"; // Ausgabe: Berlin
}
Listing 12.18: Listing 12.18 Rufen Sie keine initialisierende Methode im Konstruktorkörper auf.
Book listing lst-0256-book.cpp:
// https://godbolt.org/z/osM9ncPzr
#include <string>
#include <string_view>
using std::string; using sview = std::string_view;
struct Person {
string name_;
int alter_;
string ort_;
Person(sview n, int a, sview o)
{ // (ERR) Initialisierungsliste fehlt
init(n, a, o); // (ERR) fragwürdiger »Initialisierungsaufruf«
}
void init(sview n, int a, sview o) {
name_ = n; alter_ = a; ort_ = o;
}
};
Godbolt Listing lst-0256-godb.cpp, https://godbolt.org/z/osM9ncPzr:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/osM9ncPzr
#include <string>
#include <string_view>
using std::string; using sview = std::string_view;
struct Person {
string name_;
int alter_;
string ort_;
Person(sview n, int a, sview o)
{ // (ERR) Initialisierungsliste fehlt
init(n, a, o); // (ERR) fragwürdiger »Initialisierungsaufruf«
}
void init(sview n, int a, sview o) {
name_ = n; alter_ = a; ort_ = o;
}
};
Listing 12.19: Listing 12.19 Zugriff von außen auf die Datenfelder eines Typs
Book listing lst-0258-book.cpp:
ostream& operator<<(ostream& os, Person p) {
return os << format("{} ({}) aus {}", p.name_, p.alter_, p.ort_);
}
Listing 12.20: Listing 12.20 Teilen Sie einen Typ mit »public« und »private« in mehrere Bereiche auf.
Book listing lst-0259-book.cpp:
// https://godbolt.org/z/zrE55vWq3
#include <string>
#include <string_view>
using std::string; using std::string_view;
struct Person {
private: // alles ab hier kann von außen nicht benutzt werden
string name_;
int alter_;
string ort_;
public: // alles ab hier darf von außen verwendet werden
Person(string_view n, int a, string_view o)
: name_{n}, alter_{a}, ort_{o} { }
void drucke();
};
Godbolt Listing lst-0259-godb.cpp, https://godbolt.org/z/zrE55vWq3:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/zrE55vWq3
#include <string>
#include <string_view>
using std::string; using std::string_view;
struct Person {
private: // alles ab hier kann von außen nicht benutzt werden
string name_;
int alter_;
string ort_;
public: // alles ab hier darf von außen verwendet werden
Person(string_view n, int a, string_view o)
: name_{n}, alter_{a}, ort_{o} { }
void drucke();
};
Listing 12.21: Listing 12.21 »class« beginnt mit privater Sichtbarkeit.
Book listing lst-0260-book.cpp:
// https://godbolt.org/z/e6rqbq3bE
#include <string>
#include <string_view>
using std::string; using std::string_view;
class Person { // eine Klasse beginnt mit privater Sichtbarkeit
string name_;
int alter_;
string ort_;
public: // alles ab hier darf von außen verwendet werden
Person(string_view n, int a, string_view o)
: name_{n}, alter_{a}, ort_{o} { }
void drucke();
};
Godbolt Listing lst-0260-godb.cpp, https://godbolt.org/z/e6rqbq3bE:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/e6rqbq3bE
#include <string>
#include <string_view>
using std::string; using std::string_view;
class Person { // eine Klasse beginnt mit privater Sichtbarkeit
string name_;
int alter_;
string ort_;
public: // alles ab hier darf von außen verwendet werden
Person(string_view n, int a, string_view o)
: name_{n}, alter_{a}, ort_{o} { }
void drucke();
};
Listing 12.22: Listing 12.22 Teile der Daten sind privat.
Book listing lst-0261-book.cpp:
// https://godbolt.org/z/Pr76Y55P4
class Rect {
int area_; // private Daten
public:
int x_, y_;
void set(int x, int y) { x_=x; y_=y; area_=x_*y_; }
int calc() { return area_; }
};
Godbolt Listing lst-0261-godb.cpp, https://godbolt.org/z/Pr76Y55P4:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Pr76Y55P4
class Rect {
int area_; // private Daten
public:
int x_, y_;
void set(int x, int y) { x_=x; y_=y; area_=x_*y_; }
int calc() { return area_; }
};
Listing 12.23: Listing 12.23 Mit »= default« lassen Sie den Compiler Code erzeugen.
Book listing lst-0262-book.cpp:
// https://godbolt.org/z/PaG9nTs7s
class Rect {
int area_; // private Daten
public:
int x_, y_;
void set(int x, int y) { x_=x; y_=y; area_=x_*y_; }
int calc() { return area_; }
Rect() = default; // den Compiler einen Konstruktor generieren lassen
};
class Pow {
int result_; // private Daten; hält 'base' hoch 'exp'
public:
int base_, exp_;
void set(int b, int e) { /* ... */ }
int calc() { return result_; }
Pow() : result_{1},base_{1},exp_{1} {} // sinnvoll initialisieren
};
Godbolt Listing lst-0262-godb.cpp, https://godbolt.org/z/PaG9nTs7s:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/PaG9nTs7s
class Rect {
int area_; // private Daten
public:
int x_, y_;
void set(int x, int y) { x_=x; y_=y; area_=x_*y_; }
int calc() { return area_; }
Rect() = default; // den Compiler einen Konstruktor generieren lassen
};
class Pow {
int result_; // private Daten; hält 'base' hoch 'exp'
public:
int base_, exp_;
void set(int b, int e) { /* ... */ }
int calc() { return result_; }
Pow() : result_{1},base_{1},exp_{1} {} // sinnvoll initialisieren
};
Listing 12.24: Listing 12.24 Eigene Datentypen können vor Fehlern schützen — dies ist der erste Schritt dazu.
Book listing lst-0263-book.cpp:
// https://godbolt.org/z/r5EsnnsEG
#include <string> // string, stoi
#include <iostream> // cin, cout, ostream
#include <format>
using std::ostream; using std::format;
class Year { /* Hilfstypen für sicheres Datum */
int value_; // z. B. 2024
public:
Year(int v) : value_{v} {}
int value() { return value_; }
};
class Month {
int value_; // 1..12
public:
Month(int v) : value_{v} {}
int value() { return value_; }
};
class Day {
int value_; // 1..31
public:
Day(int v) : value_{v} {}
int value() { return value_; }
};
/* typsicher konstruierendes Datum */
class Date {
Year year_;
Month month_ = 1;
Day day_ = 1;
public:
Date(int y) : year_{y} // 1-Argument-Konstruktor
{} // setzt 1. Januar des angegebenen Jahres
Date(Year y, Month m, Day d) // 3-Argument-Konstruktor
: year_{y}, month_{m}, day_{d}
{}
ostream& print(ostream& os); // z. B. 2024-04-20
};
ostream& Date::print(ostream& os) { // z. B. 2024-04-20
return os << format("{}-{:02}-{:02}",
year_.value(), month_.value(), day_.value());
}
ostream& operator<<(ostream& os, Date d) {
return d.print(os);
}
// http://codegolf.stackexchange.com/a/11146/1405, user Fors, 2014-02-25
Date ostern(Year year) {
const int y = year.value();
int a = y/100*1483 - y/400*2225 + 2613;
int b = (y%19*3510 + a/25*319)/330%29;
b = 148 - b - (y*5/4 + a - b)%7;
return Date{Year{y}, Month{b/31}, Day{b%31 + 1}}; // Datum erzeugen
}
int main(int argc, const char *argv[] ) {
/* Eingabe */
int zahl {};
if(argc > 1) {
zahl = std::stoi(argv[1]);
} else {
std::cout << "Jahr? "; std::cin >> zahl;
}
/* Berechnung */
Date date = ostern(zahl); // implizite Konvertierung nach Year
/* Ausgabe */
std::cout << "Ostern: " << date << "\n";
}
Godbolt Listing lst-0263-godb.cpp, https://godbolt.org/z/r5EsnnsEG:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/r5EsnnsEG
#include <string> // string, stoi
#include <iostream> // cin, cout, ostream
#include <format>
using std::ostream; using std::format;
class Year { /* Hilfstypen für sicheres Datum */
int value_; // z. B. 2024
public:
Year(int v) : value_{v} {}
int value() { return value_; }
};
class Month {
int value_; // 1..12
public:
Month(int v) : value_{v} {}
int value() { return value_; }
};
class Day {
int value_; // 1..31
public:
Day(int v) : value_{v} {}
int value() { return value_; }
};
/* typsicher konstruierendes Datum */
class Date {
Year year_;
Month month_ = 1;
Day day_ = 1;
public:
Date(int y) : year_{y} // 1-Argument-Konstruktor
{} // setzt 1. Januar des angegebenen Jahres
Date(Year y, Month m, Day d) // 3-Argument-Konstruktor
: year_{y}, month_{m}, day_{d}
{}
ostream& print(ostream& os); // z. B. 2024-04-20
};
ostream& Date::print(ostream& os) { // z. B. 2024-04-20
return os << format("{}-{:02}-{:02}",
year_.value(), month_.value(), day_.value());
}
ostream& operator<<(ostream& os, Date d) {
return d.print(os);
}
// http://codegolf.stackexchange.com/a/11146/1405, user Fors, 2014-02-25
Date ostern(Year year) {
const int y = year.value();
int a = y/100*1483 - y/400*2225 + 2613;
int b = (y%19*3510 + a/25*319)/330%29;
b = 148 - b - (y*5/4 + a - b)%7;
return Date{Year{y}, Month{b/31}, Day{b%31 + 1}}; // Datum erzeugen
}
int main(int argc, const char *argv[] ) {
/* Eingabe */
int zahl {};
if(argc > 1) {
zahl = std::stoi(argv[1]);
} else {
std::cout << "Jahr? "; std::cin >> zahl;
}
/* Berechnung */
Date date = ostern(zahl); // implizite Konvertierung nach Year
/* Ausgabe */
std::cout << "Ostern: " << date << "\n";
}
Listing 12.25: Listing 12.25 Wenn alle »return«-Anweisungen dieselbe Variable zurückliefern, kann der Compiler eine Kopie immer vermeiden.
Book listing lst-0272-book.cpp:
// https://godbolt.org/z/T7afh4vxz
#include <vector>
std::vector<int> createData(unsigned size) {
std::vector<int> result{};
for(int idx=0; idx<size; ++idx) {
result.push_back(idx);
}
return result;
}
Godbolt Listing lst-0272-godb.cpp, https://godbolt.org/z/T7afh4vxz:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/T7afh4vxz
#include <vector>
std::vector<int> createData(unsigned size) {
std::vector<int> result{};
for(int idx=0; idx<size; ++idx) {
result.push_back(idx);
}
return result;
}
Listing 12.26: Listing 12.26 Mit »explicit« verhindern Sie automatische Typumwandlung.
Book listing lst-0281-book.cpp:
// jeweils nur Auszüge
class Year {
explicit Year(int v) : value_{v} {}
};
class Month {
explicit Month(int v) : value_{v} {}
};
class Day {
explicit Day(int v) : value_{v} {}
};
class Date {
explicit Date(int y) : year_{y} {}
};
Listing 12.27: Listing 12.27 »Year« hat nun kein »value()« mehr und benötigt dafür andere Methoden.
Book listing lst-0291-book.cpp:
// https://godbolt.org/z/EPz4Kd6jP
class Year {
int value_;
public:
explicit Year(int v) : value_{v} {}
std::ostream& print(std::ostream& os) const;
Year& advance(const Year& other);
bool equals(const Year& other) const;
bool less_than(const Year& other) const;
};
std::ostream& Year::print(std::ostream& os) const {
return os << value_;
}
std::ostream& operator<<(std::ostream& os, const Year& year) {
return year.print(os);
}
Year& Year::advance(const Year& other) {
value_ += other.value_;
return *this;
}
bool Year::equals(const Year& other) const {
return value_ == other.value_;
}
bool Year::less_than(const Year& other) const {
return value_ < other.value_;
}
Godbolt Listing lst-0291-godb.cpp, https://godbolt.org/z/EPz4Kd6jP:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/EPz4Kd6jP
class Year {
int value_;
public:
explicit Year(int v) : value_{v} {}
std::ostream& print(std::ostream& os) const;
Year& advance(const Year& other);
bool equals(const Year& other) const;
bool less_than(const Year& other) const;
};
std::ostream& Year::print(std::ostream& os) const {
return os << value_;
}
std::ostream& operator<<(std::ostream& os, const Year& year) {
return year.print(os);
}
Year& Year::advance(const Year& other) {
value_ += other.value_;
return *this;
}
bool Year::equals(const Year& other) const {
return value_ == other.value_;
}
bool Year::less_than(const Year& other) const {
return value_ < other.value_;
}
Listing 12.28: Listing 12.28 Gibt »advance« das Objekt selbst zurück, können Sie danach eine weitere Methode aufrufen.
Book listing lst-0292-book.cpp:
Year year{2024};
year.advance(Year{1}).advance(Year{3});
cout << year; // Ausgabe: 2028
Listing 12.29: Listing 12.29 Eine fließende Programmierschnittstelle erlaubt zuweilen übersichtlichen Code.
Book listing lst-0293-book.cpp:
Page page = Html().body()
.h1("Ueberschrift")
.table().border(0)
.tr()
.td().css("head").text("Hunderasse").end()
.td().text("Pudel").end()
.end()
.end()
.toPage();
Listing 12.30: Listing 12.30 Der eigentlich interne Typ »int« ist Teil der Schnittstelle der Klasse geworden.
Book listing lst-0294-book.cpp:
// https://godbolt.org/z/sP3W8jx6E
class Year {
int value_; // eigentlich intern verwendeter Typ
public:
explicit Year(int v) : value_{v} {} // Typ wird Teil des Interface
int value() { return value_; } // auch bei der Rückgabe
};
int main() {
Year year{ 2024 }; // Typ int
int val = year.value(); // passender Typ
}
Godbolt Listing lst-0294-godb.cpp, https://godbolt.org/z/sP3W8jx6E:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/sP3W8jx6E
class Year {
int value_; // eigentlich intern verwendeter Typ
public:
explicit Year(int v) : value_{v} {} // Typ wird Teil des Interface
int value() { return value_; } // auch bei der Rückgabe
};
int main() {
Year year{ 2024 }; // Typ int
int val = year.value(); // passender Typ
}
Listing 12.31: Listing 12.31 Mit »using« können Sie Typaliase einführen, mit denen sich Interfaces leichter pflegen lassen als mit den Typen selbst.
Book listing lst-0295-book.cpp:
// https://godbolt.org/z/r3xaPv5Mr
class Year {
public:
using value_type = int; // Typalias einführen
value_type value_; // eigentlich intern verwendeter Typ
public:
explicit Year(value_type v) : value_{v} {}
value_type value() { return value_; }
};
int main() {
Year year{ 2024 }; // hier auf Compilerkonvertierung zählen
Year::value_type val = year.value(); // verwenden Sie ::
}
Godbolt Listing lst-0295-godb.cpp, https://godbolt.org/z/r3xaPv5Mr:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/r3xaPv5Mr
class Year {
public:
using value_type = int; // Typalias einführen
value_type value_; // eigentlich intern verwendeter Typ
public:
explicit Year(value_type v) : value_{v} {}
value_type value() { return value_; }
};
int main() {
Year year{ 2024 }; // hier auf Compilerkonvertierung zählen
Year::value_type val = year.value(); // verwenden Sie ::
}
Listing 12.32: Listing 12.32 Auch die Standardbibliothek enthält viele praktische Typaliase.
Book listing lst-0296-book.cpp:
// https://godbolt.org/z/vjTWjfKKz
#include <vector>
#include <set>
#include <iostream>
using std::vector; using std::set; using std::cout;
using vector_t = vector<unsigned long long>; // Ihr eigener Typalias
int main() {
vector_t huge{ 12ULL, 10'000'000'000ULL, 9ULL, 0ULL, };
vector_t::size_type sz = huge.size();
vector_t::value_type uiuiui = huge[1];
for(vector_t::iterator it = huge.begin(); it != huge.end(); ++it)
*it *= 2; // verdoppeln
/* sortieren per set */
set<vector_t::value_type> sortiert{huge.begin(), huge.end()};
for(vector_t::value_type val : sortiert)
cout << val << " ";
cout << "\n";
}
Godbolt Listing lst-0296-godb.cpp, https://godbolt.org/z/vjTWjfKKz:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/vjTWjfKKz
#include <vector>
#include <set>
#include <iostream>
using std::vector; using std::set; using std::cout;
using vector_t = vector<unsigned long long>; // Ihr eigener Typalias
int main() {
vector_t huge{ 12ULL, 10'000'000'000ULL, 9ULL, 0ULL, };
vector_t::size_type sz = huge.size();
vector_t::value_type uiuiui = huge[1];
for(vector_t::iterator it = huge.begin(); it != huge.end(); ++it)
*it *= 2; // verdoppeln
/* sortieren per set */
set<vector_t::value_type> sortiert{huge.begin(), huge.end()};
for(vector_t::value_type val : sortiert)
cout << val << " ";
cout << "\n";
}
Listing 12.33: Listing 12.33 Bei der Initialisierung einer Variablen kann der Compiler den Typ ermitteln.
Book listing lst-0300-book.cpp:
// https://godbolt.org/z/Wh71cf7j1
#include <vector>
#include <set>
#include <iostream> // cout
using std::vector; using std::set; using std::cout;
using vector_t = vector<unsigned long long>; // Ihr eigener Typalias
int main() {
vector_t huge{ 12ULL, 10000000000ULL, 9ULL, 0ULL, };
auto sz = huge.size();
auto uiuiui = huge[1];
for(auto it = huge.begin(); it != huge.end(); ++it)
*it *= 2; // verdoppeln
/* sortieren per set */
set sortiert(huge.begin(), huge.end()); // set<vector_t::value_type>
for(auto val : sortiert)
cout << val << " ";
cout << "\n";
}
Godbolt Listing lst-0300-godb.cpp, https://godbolt.org/z/Wh71cf7j1:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Wh71cf7j1
#include <vector>
#include <set>
#include <iostream> // cout
using std::vector; using std::set; using std::cout;
using vector_t = vector<unsigned long long>; // Ihr eigener Typalias
int main() {
vector_t huge{ 12ULL, 10000000000ULL, 9ULL, 0ULL, };
auto sz = huge.size();
auto uiuiui = huge[1];
for(auto it = huge.begin(); it != huge.end(); ++it)
*it *= 2; // verdoppeln
/* sortieren per set */
set sortiert(huge.begin(), huge.end()); // set<vector_t::value_type>
for(auto val : sortiert)
cout << val << " ";
cout << "\n";
}
Listing 12.34: Listing 12.34 Typ-Deduktion mit »auto« können Sie mit einem Concept weiter einschränken.
Book listing lst-0301-book.cpp:
// https://godbolt.org/z/hT8o3dqrK
#include <vector>
#include <set>
#include <iostream> // cout
#include <concepts> // integral
#include <iterator> // output_iterator, input_iterator
using namespace std;
using vector_t = vector<unsigned long long>; // Ihr eigener Typalias
int main() {
vector_t huge{ 12ULL, 10000000000ULL, 9ULL, 0ULL, };
unsigned_integral auto sz = huge.size();
unsigned_integral auto uiuiui = huge[1];
signed_integral auto meh = huge[1]; // (ERR) Concept nicht erfüllt
input_or_output_iterator auto itx = huge.begin(); // Concept ohne Parameter
for(output_iterator<unsigned long long> auto i=huge.begin();
it!=huge.end(); ++it)
*it *= 2; // verdoppeln
/* sortieren per set */
set sortiert(huge.begin(), huge.end()); // set<vector_t::value_type>
for(const unsigned_integral auto& val : sortiert)
cout << val << " ";
cout << "\n";
}
Godbolt Listing lst-0301-godb.cpp, https://godbolt.org/z/hT8o3dqrK:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/hT8o3dqrK
#include <vector>
#include <set>
#include <iostream> // cout
#include <concepts> // integral
#include <iterator> // output_iterator, input_iterator
using namespace std;
using vector_t = vector<unsigned long long>; // Ihr eigener Typalias
int main() {
vector_t huge{ 12ULL, 10000000000ULL, 9ULL, 0ULL, };
unsigned_integral auto sz = huge.size();
unsigned_integral auto uiuiui = huge[1];
signed_integral auto meh = huge[1]; // (ERR) Concept nicht erfüllt
input_or_output_iterator auto itx = huge.begin(); // Concept ohne Parameter
for(output_iterator<unsigned long long> auto i=huge.begin();
it!=huge.end(); ++it)
*it *= 2; // verdoppeln
/* sortieren per set */
set sortiert(huge.begin(), huge.end()); // set<vector_t::value_type>
for(const unsigned_integral auto& val : sortiert)
cout << val << " ";
cout << "\n";
}
Listing 12.35: Listing 12.35 Wenn Sie »auto« mit »&« anreichern, erhalten Sie eine veränderbare Referenz.
Book listing lst-0302-book.cpp:
// https://godbolt.org/z/ro6fdsvT9
#include <vector>
#include <iostream> // cout
using std::vector; using std::cout;
int main() {
vector data{ 12, 100, -1, 0, }; // vector<int>
for(auto& val : data)
val *= 2; // verdoppeln
for(const auto val : data)
cout << val << " ";
cout << "\n";
}
Godbolt Listing lst-0302-godb.cpp, https://godbolt.org/z/ro6fdsvT9:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/ro6fdsvT9
#include <vector>
#include <iostream> // cout
using std::vector; using std::cout;
int main() {
vector data{ 12, 100, -1, 0, }; // vector<int>
for(auto& val : data)
val *= 2; // verdoppeln
for(const auto val : data)
cout << val << " ";
cout << "\n";
}
Listing 12.36: Listing 12.36 Um einen eigenen Datentyp in einen »vector« zu packen, muss dieser nicht viele Bedingungen erfüllen.
Book listing lst-0306-book.cpp:
// https://godbolt.org/z/8ejPs6zr6
#include <vector>
struct Zahl {
int wert_ = 0;
Zahl() {} // Standardkonstruktor
explicit Zahl(int w) : wert_{w} {}
};
int main() {
std::vector<Zahl> zahlen{}; // okay: Zahl erfüllt die Bedingungen
zahlen.push_back( Zahl{2} );
}
Godbolt Listing lst-0306-godb.cpp, https://godbolt.org/z/8ejPs6zr6:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/8ejPs6zr6
#include <vector>
struct Zahl {
int wert_ = 0;
Zahl() {} // Standardkonstruktor
explicit Zahl(int w) : wert_{w} {}
};
int main() {
std::vector<Zahl> zahlen{}; // okay: Zahl erfüllt die Bedingungen
zahlen.push_back( Zahl{2} );
}
Listing 12.37: Listing 12.37 Für einen »set« eines eigenen Datentyps müssen Sie »operator<« überschreiben.
Book listing lst-0307-book.cpp:
// https://godbolt.org/z/vrdKPvh7f
#include <set>
struct Zahl {
int wert_ = 0;
explicit Zahl(int w) : wert_{w} {}
};
bool operator<(const Zahl& links, const Zahl& rechts) {
return links.wert_ < rechts.wert_;
}
int main() {
std::set<Zahl> zahlen{}; // okay
zahlen.insert( Zahl{3} ); // hier wird operator< gebraucht
}
Godbolt Listing lst-0307-godb.cpp, https://godbolt.org/z/vrdKPvh7f:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/vrdKPvh7f
#include <set>
struct Zahl {
int wert_ = 0;
explicit Zahl(int w) : wert_{w} {}
};
bool operator<(const Zahl& links, const Zahl& rechts) {
return links.wert_ < rechts.wert_;
}
int main() {
std::set<Zahl> zahlen{}; // okay
zahlen.insert( Zahl{3} ); // hier wird operator< gebraucht
}
GodboltId:M81MjePh5
Book listing lst-0308-book.cpp:
// https://godbolt.org/z/M81MjePh5
#include <map>
struct Zahl {
int wert_ = 0;
explicit Zahl(int w) : wert_{w} {}
};
bool operator<(const Zahl& links, const Zahl& rechts) {
return links.wert_ < rechts.wert_;
}
int main() {
std::map<Zahl,int> zahlen{}; // okay
zahlen.insert( std::make_pair(Zahl{4},100) ); // braucht operator<
zahlen[Zahl{5}] = 200; // hier ebenfalls
}
Godbolt Listing lst-0308-godb.cpp, https://godbolt.org/z/M81MjePh5:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/M81MjePh5
#include <map>
struct Zahl {
int wert_ = 0;
explicit Zahl(int w) : wert_{w} {}
};
bool operator<(const Zahl& links, const Zahl& rechts) {
return links.wert_ < rechts.wert_;
}
int main() {
std::map<Zahl,int> zahlen{}; // okay
zahlen.insert( std::make_pair(Zahl{4},100) ); // braucht operator<
zahlen[Zahl{5}] = 200; // hier ebenfalls
}
Listing 13.1: Sie definieren einen Namensraum mit »namespace«.
Book listing lst-0311-book.cpp:
// https://godbolt.org/z/T1ohsxbje
#include <string>
#include <iostream> // ostream, cout
namespace plant {
class Baum {
std::string name_;
public:
explicit Baum(const std::string_view name) : name_{name} {}
void print(std::ostream& os) const { os << name_; }
};
std::ostream& operator<<(std::ostream& os, const Baum& arg)
{ arg.print(os); return os; }
using NadelBaum = Baum; // für spätere Erweiterungen …
using LaubBaum = Baum; // … vorsorgen
namespace beispielnamen { // eingebetteter Namensraum
std::string eicheName = "Eiche";
std::string bucheName = "Buche";
std::string tanneName = "Tanne";
} // Ende namespace beispielnamen
} // Ende namespace plant
int main() { // main darf nicht in einem Namespace stehen
using namespace plant::beispielnamen; // alle Beispielnamen verfügbar machen
plant::NadelBaum tanne{ tanneName };
plant::LaubBaum eiche{ eicheName };
tanne.print(std::cout); std::cout << "\n";
using plant::operator<<; // ohne geht 'cout << eiche' nicht
std::cout << eiche << "\n";
}
Godbolt Listing lst-0311-godb.cpp, https://godbolt.org/z/T1ohsxbje:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/T1ohsxbje
#include <string>
#include <iostream> // ostream, cout
namespace plant {
class Baum {
std::string name_;
public:
explicit Baum(const std::string_view name) : name_{name} {}
void print(std::ostream& os) const { os << name_; }
};
std::ostream& operator<<(std::ostream& os, const Baum& arg)
{ arg.print(os); return os; }
using NadelBaum = Baum; // für spätere Erweiterungen …
using LaubBaum = Baum; // … vorsorgen
namespace beispielnamen { // eingebetteter Namensraum
std::string eicheName = "Eiche";
std::string bucheName = "Buche";
std::string tanneName = "Tanne";
} // Ende namespace beispielnamen
} // Ende namespace plant
int main() { // main darf nicht in einem Namespace stehen
using namespace plant::beispielnamen; // alle Beispielnamen verfügbar machen
plant::NadelBaum tanne{ tanneName };
plant::LaubBaum eiche{ eicheName };
tanne.print(std::cout); std::cout << "\n";
using plant::operator<<; // ohne geht 'cout << eiche' nicht
std::cout << eiche << "\n";
}
Listing 13.2: In getrennten Namensräumen können Sie die gleichen Operatoren definieren.
Book listing lst-0315-book.cpp:
namespace plant {
// … wie zuvor …
std::ostream& operator<<(std::ostream&, const Baum&) {…};
namespace debug {
std::ostream& operator<<(std::ostream&, const Baum&) {…};
}
}
plant::Baum baum{"MeinBaum"};
void run() {
using namespace plant;
cout << baum << "\n";
}
void diagnostic() {
using namespace plant::debug;
cout << baum << "\n";
}
int main() {
run();
diagnostic();
}
Listing 13.3: Ein anonymer Namensraum macht Definitionen lokal für die aktuelle Datei.
Book listing lst-0316-book.cpp:
// https://godbolt.org/z/M6EnPT3Gr
// modul.hpp
#include <string>
#include <iostream>
namespace plant {
class Baum {
std::string name_;
public:
explicit Baum(const std::string_view name);
void print(std::ostream& os) const;
};
std::ostream& operator<<(std::ostream& os, const Baum& arg);
}
// modul.cpp
#include "modul.hpp"
namespace { // anonymer Namensraum
std::string PREFIX = "BAUM:";
void printInfo(std::ostream& os) {
os << "Autor: Torsten T. Will\n";
}
}
bool debug = false; // global, kein Namensraum
namespace plant {
Baum::Baum(const std::string_view name)
: name_{name} {}
void Baum::print(std::ostream& os) const {
os << PREFIX << name_;
}
std::ostream& operator<<(std::ostream& os, const Baum& arg) {
if(debug) printInfo(os);
arg.print(os); return os;
}
}
// main.cpp
#include "modul.hpp"
int main() {
plant::Baum x{"x"};
x.print(std::cout); std::cout << "\n";
}
Godbolt Listing lst-0316-godb.cpp, https://godbolt.org/z/M6EnPT3Gr:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/M6EnPT3Gr
// modul.hpp
#include <string>
#include <iostream>
namespace plant {
class Baum {
std::string name_;
public:
explicit Baum(const std::string_view name);
void print(std::ostream& os) const;
};
std::ostream& operator<<(std::ostream& os, const Baum& arg);
}
// modul.cpp
#include "modul.hpp"
namespace { // anonymer Namensraum
std::string PREFIX = "BAUM:";
void printInfo(std::ostream& os) {
os << "Autor: Torsten T. Will\n";
}
}
bool debug = false; // global, kein Namensraum
namespace plant {
Baum::Baum(const std::string_view name)
: name_{name} {}
void Baum::print(std::ostream& os) const {
os << PREFIX << name_;
}
std::ostream& operator<<(std::ostream& os, const Baum& arg) {
if(debug) printInfo(os);
arg.print(os); return os;
}
}
// main.cpp
#include "modul.hpp"
int main() {
plant::Baum x{"x"};
x.print(std::cout); std::cout << "\n";
}
GodboltId:cTYhMfo5W
Book listing lst-0317-book.cpp:
// https://godbolt.org/z/cTYhMfo5W
// modul.cpp
#include "modul.hpp"
static std::string PREFIX = "BAUM:";
static void printInfo(std::ostream& os) {
os << "Autor: Torsten T. Will\n";
}
bool debug = false;
// Rest wie bisher
Godbolt Listing lst-0317-godb.cpp, https://godbolt.org/z/cTYhMfo5W:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/cTYhMfo5W
// modul.cpp
#include "modul.hpp"
static std::string PREFIX = "BAUM:";
static void printInfo(std::ostream& os) {
os << "Autor: Torsten T. Will\n";
}
bool debug = false;
// Rest wie bisher
Listing 13.4: Alle Instanzen teilen sich ihre »static«-Datenfelder und -Methoden.
Book listing lst-0319-book.cpp:
// https://godbolt.org/z/n4e8xdEGj
#include <iostream> // cout
#include <string>
using std::string;
class Tree {
static size_t countConstructed_;
static size_t countDestructed_;
string kind_;
Tree(string kind) : kind_{kind} // privater Konstruktor
{ ++countConstructed_; }
public:
Tree(const Tree& o) : kind_{o.kind_}
{ ++countConstructed_; }
string getKind() const { return kind_; }
~Tree() { ++countDestructed_; }
static Tree create(string kind) { return Tree{kind}; }
static void stats(std::ostream& os) {
os << "Constructed:+" << countConstructed_
<< " Destructed:-" << countDestructed_ << "\n";
}
};
size_t Tree::countConstructed_ = 0;
size_t Tree::countDestructed_ = 0;
int main() {
Tree birke = Tree::create("Birke");
for(auto kind : {"Esche", "Eibe", "Eiche"}) {
Tree temp = Tree::create(kind);
std::cout << temp.getKind() << "\n";
}
Tree::stats(std::cout);
}
Godbolt Listing lst-0319-godb.cpp, https://godbolt.org/z/n4e8xdEGj:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/n4e8xdEGj
#include <iostream> // cout
#include <string>
using std::string;
class Tree {
static size_t countConstructed_;
static size_t countDestructed_;
string kind_;
Tree(string kind) : kind_{kind} // privater Konstruktor
{ ++countConstructed_; }
public:
Tree(const Tree& o) : kind_{o.kind_}
{ ++countConstructed_; }
string getKind() const { return kind_; }
~Tree() { ++countDestructed_; }
static Tree create(string kind) { return Tree{kind}; }
static void stats(std::ostream& os) {
os << "Constructed:+" << countConstructed_
<< " Destructed:-" << countDestructed_ << "\n";
}
};
size_t Tree::countConstructed_ = 0;
size_t Tree::countDestructed_ = 0;
int main() {
Tree birke = Tree::create("Birke");
for(auto kind : {"Esche", "Eibe", "Eiche"}) {
Tree temp = Tree::create(kind);
std::cout << temp.getKind() << "\n";
}
Tree::stats(std::cout);
}
GodboltId:b9arcEMM1
Book listing lst-0321-book.cpp:
// https://godbolt.org/z/b9arcEMM1
constinit auto SZ = 10*1000-1; // globale Variable
size_t autoincrement() {
static constinit size_t i = 0; // lokale statische Variable
return i++;
}
class BraitenbergVehicle {
inline static constinit size_t count_ = 0; // Klassenvariable
public:
size_t id_;
BraitenbergVehicle() : id_{++count_} {}
~BraitenbergVehicle() { --count_; }
};
Godbolt Listing lst-0321-godb.cpp, https://godbolt.org/z/b9arcEMM1:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/b9arcEMM1
constinit auto SZ = 10*1000-1; // globale Variable
size_t autoincrement() {
static constinit size_t i = 0; // lokale statische Variable
return i++;
}
class BraitenbergVehicle {
inline static constinit size_t count_ = 0; // Klassenvariable
public:
size_t id_;
BraitenbergVehicle() : id_{++count_} {}
~BraitenbergVehicle() { --count_; }
};
Listing 13.5: Eine lokale statische Variable wird einmal initialisiert und danach wiederverwendet.
Book listing lst-0322-book.cpp:
// https://godbolt.org/z/h5qond6db
#include <iostream> // cout
class Keyboard {
Keyboard(const Keyboard&) = delete; // keine Kopie
const size_t nr_; // aktuelle Nummer
public:
static inline size_t count_ = 0; // zählt erzeugte Instanzen
explicit Keyboard() : nr_{count_++} {
std::cout << " Keyboard().nr:"<<nr_<<"\n";
}
};
Keyboard& getKeyboard() {
std::cout << " getKeyboard()\n";
static Keyboard keyboard{}; // statische lokale Variable
return keyboard;
}
void func() {
std::cout << "kbFunc...\n";
Keyboard& kbFunc = getKeyboard();
}
int main() {
std::cout << "kbA...\n";
Keyboard& kbA = getKeyboard();
func();
std::cout << "kbB...\n";
Keyboard& kbB = getKeyboard();
std::cout << "count:" << Keyboard::count_ << "\n";
}
Godbolt Listing lst-0322-godb.cpp, https://godbolt.org/z/h5qond6db:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/h5qond6db
#include <iostream> // cout
class Keyboard {
Keyboard(const Keyboard&) = delete; // keine Kopie
const size_t nr_; // aktuelle Nummer
public:
static inline size_t count_ = 0; // zählt erzeugte Instanzen
explicit Keyboard() : nr_{count_++} {
std::cout << " Keyboard().nr:"<<nr_<<"\n";
}
};
Keyboard& getKeyboard() {
std::cout << " getKeyboard()\n";
static Keyboard keyboard{}; // statische lokale Variable
return keyboard;
}
void func() {
std::cout << "kbFunc...\n";
Keyboard& kbFunc = getKeyboard();
}
int main() {
std::cout << "kbA...\n";
Keyboard& kbA = getKeyboard();
func();
std::cout << "kbB...\n";
Keyboard& kbB = getKeyboard();
std::cout << "count:" << Keyboard::count_ << "\n";
}
Listing 13.6: Das Meyers-Singleton
Book listing lst-0323-book.cpp:
Keyboard& getKeyboard() {
cout << " getKeyboard()\n";
static Keyboard keyboard{}; // statische lokale Variable
return keyboard;
}
Listing 13.7: Die Bezeichner eines inline namespace gehen zusätzlich in seinen umgebenden Namensraum.
Book listing lst-0324-book.cpp:
// https://godbolt.org/z/115M1csEE
#include <iostream>
namespace mylib {
namespace v1 {
int version() { return 1; }
}
inline namespace v2 { // aktuelle Version
int version() { return 2; }
}
}
int main() {
std::cout << "Version " << mylib::version() << "\n"; // Ausgabe: 2
std::cout << "Version " << mylib::v1::version() << "\n"; // Ausgabe: 1
std::cout << "Version " << mylib::v2::version() << "\n"; // Ausgabe: 2
}
Godbolt Listing lst-0324-godb.cpp, https://godbolt.org/z/115M1csEE:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/115M1csEE
#include <iostream>
namespace mylib {
namespace v1 {
int version() { return 1; }
}
inline namespace v2 { // aktuelle Version
int version() { return 2; }
}
}
int main() {
std::cout << "Version " << mylib::version() << "\n"; // Ausgabe: 2
std::cout << "Version " << mylib::v1::version() << "\n"; // Ausgabe: 1
std::cout << "Version " << mylib::v2::version() << "\n"; // Ausgabe: 2
}
GodboltId:WTWxYa3rd
Book listing lst-0334-book.cpp:
// https://godbolt.org/z/WTWxYa3rd
class Widget {
unsigned x = 0, y = 0, w = 0, h = 0; // zum Beispiel
public:
unsigned getLeft() const;
unsigned getTop() const;
unsigned getRight() const;
unsigned getBottom() const;
void setWidth(unsigned w);
void setHeight(unsigned h);
};
Godbolt Listing lst-0334-godb.cpp, https://godbolt.org/z/WTWxYa3rd:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/WTWxYa3rd
class Widget {
unsigned x = 0, y = 0, w = 0, h = 0; // zum Beispiel
public:
unsigned getLeft() const;
unsigned getTop() const;
unsigned getRight() const;
unsigned getBottom() const;
void setWidth(unsigned w);
void setHeight(unsigned h);
};
Listing 13.8: Lokale Konstanten einer Datei passen gut in einen anonymen Namensraum.
Book listing lst-0339-book.cpp:
// https://godbolt.org/z/q3Ga7hTGa
#include <vector>
namespace { // anonymer Namensraum für Konstanten
const unsigned DATA_SIZE = 100; /* Anzahl Elemente in Data */
const double LIMIT = 999.999; /* Maxwert bei Initialisierung */
};
std::vector<int> createData() {
std::vector<int> result(DATA_SIZE);
double currVal = 1.0;
for(auto &elem : result) {
elem = currVal;
currVal *= 2; // nächster Wert ist größer
if(currVal > LIMIT) {
currVal = LIMIT; // kein Wert darf größer sein
}
}
return result;
}
Godbolt Listing lst-0339-godb.cpp, https://godbolt.org/z/q3Ga7hTGa:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/q3Ga7hTGa
#include <vector>
namespace { // anonymer Namensraum für Konstanten
const unsigned DATA_SIZE = 100; /* Anzahl Elemente in Data */
const double LIMIT = 999.999; /* Maxwert bei Initialisierung */
};
std::vector<int> createData() {
std::vector<int> result(DATA_SIZE);
double currVal = 1.0;
for(auto &elem : result) {
elem = currVal;
currVal *= 2; // nächster Wert ist größer
if(currVal > LIMIT) {
currVal = LIMIT; // kein Wert darf größer sein
}
}
return result;
}
GodboltId:9Esx13h9r
Book listing lst-0340-book.cpp:
// https://godbolt.org/z/9Esx13h9r
struct Widget {
int num_ = 0;
void setNumber(int x) { // eine Nicht-const-Methode
num_=x;
}
};
Widget createWidget() { // Rückgabe als Wert
Widget result{}; // Erzeugen
return result;
}
int main() {
Widget w = createWidget(); // Rückgabe als Wert erzeugt Kopie
w.setNumber(100); // verändern, natürlich okay, w ist nicht-const
}
Godbolt Listing lst-0340-godb.cpp, https://godbolt.org/z/9Esx13h9r:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/9Esx13h9r
struct Widget {
int num_ = 0;
void setNumber(int x) { // eine Nicht-const-Methode
num_=x;
}
};
Widget createWidget() { // Rückgabe als Wert
Widget result{}; // Erzeugen
return result;
}
int main() {
Widget w = createWidget(); // Rückgabe als Wert erzeugt Kopie
w.setNumber(100); // verändern, natürlich okay, w ist nicht-const
}
Listing 13.9: Obwohl der Rückgabetyp hier mit »const« markiert ist, wirkt es sich nicht aus, denn es wird immer kopiert.
Book listing lst-0341-book.cpp:
// https://godbolt.org/z/erv34b67c
const Widget createWidget() { // Rückgabe als const-Wert
Widget result{};
return result;
}
int main() {
Widget w = createWidget(); // kopiert in neues nicht-const w
w.setNumber(100); // w ist nicht-const, verändern ist okay
}
Godbolt Listing lst-0341-godb.cpp, https://godbolt.org/z/erv34b67c:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/erv34b67c
const Widget createWidget() { // Rückgabe als const-Wert
Widget result{};
return result;
}
int main() {
Widget w = createWidget(); // kopiert in neues nicht-const w
w.setNumber(100); // w ist nicht-const, verändern ist okay
}
Listing 13.10: Konstante Referenzen in Rückgaben
Book listing lst-0342-book.cpp:
// https://godbolt.org/z/v1TP6aYxT
#include <string>
#include <string_view>
using std::string; using std::string_view;
class Widget {
string name_ = "";
public:
void setName(string_view newName) {
name_ = newName;
}
const string& getName() const { // const&-Rückgabe
return name_;
}
};
int main() {
Widget w{};
w.setName("Titel");
string name1 = w.getName(); // neuer String, also Kopie
name1.clear(); // die Kopie dürfen Sie wieder verändern
const string& name2 = w.getName(); // const-Referenz auf inneren string name_
/* name2.clear(); */ // name2 ist const, geht also nicht
string& name3 = w.getName(); // (ERR) Funktion gibt const& zurück, nicht &.
auto name4 = w.getName(); // identisch mit name1
const auto& name5 = w.getName(); // identisch mit name2
}
Godbolt Listing lst-0342-godb.cpp, https://godbolt.org/z/v1TP6aYxT:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/v1TP6aYxT
#include <string>
#include <string_view>
using std::string; using std::string_view;
class Widget {
string name_ = "";
public:
void setName(string_view newName) {
name_ = newName;
}
const string& getName() const { // const&-Rückgabe
return name_;
}
};
int main() {
Widget w{};
w.setName("Titel");
string name1 = w.getName(); // neuer String, also Kopie
name1.clear(); // die Kopie dürfen Sie wieder verändern
const string& name2 = w.getName(); // const-Referenz auf inneren string name_
/* name2.clear(); */ // name2 ist const, geht also nicht
string& name3 = w.getName(); // (ERR) Funktion gibt const& zurück, nicht &.
auto name4 = w.getName(); // identisch mit name1
const auto& name5 = w.getName(); // identisch mit name2
}
Listing 13.11: Referenzen können konstant und nicht konstant zurückgegeben werden.
Book listing lst-0343-book.cpp:
// https://godbolt.org/z/rMrKbrdWe
#include <string>
#include <iostream>
using std::string; using std::cout;
class Widget {
string name_{};
public:
const string& readName() const; // const&-Rückgabe, const-Methode
string& getName(); // &-Rückgabe
};
const string& Widget::readName() const { return name_; }
string& Widget::getName() { return name_; }
int main() {
Widget w{};
const string& readonly = w.readName(); // const&, unveränderbar
cout << "Name: " << readonly << "\n"; // noch "" leer.
string& readwrite = w.getName(); // &, veränderbar
readwrite.append("dran"); // verändert auch name_ und readonly
cout << "Name per readwrite: " << readwrite << "\n"; // "dran"
cout << "Name per readonly: " << readonly << "\n"; // auch "dran"
}
Godbolt Listing lst-0343-godb.cpp, https://godbolt.org/z/rMrKbrdWe:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/rMrKbrdWe
#include <string>
#include <iostream>
using std::string; using std::cout;
class Widget {
string name_{};
public:
const string& readName() const; // const&-Rückgabe, const-Methode
string& getName(); // &-Rückgabe
};
const string& Widget::readName() const { return name_; }
string& Widget::getName() { return name_; }
int main() {
Widget w{};
const string& readonly = w.readName(); // const&, unveränderbar
cout << "Name: " << readonly << "\n"; // noch "" leer.
string& readwrite = w.getName(); // &, veränderbar
readwrite.append("dran"); // verändert auch name_ und readonly
cout << "Name per readwrite: " << readwrite << "\n"; // "dran"
cout << "Name per readonly: " << readonly << "\n"; // auch "dran"
}
GodboltId:hsWrnaEea
Book listing lst-0346-book.cpp:
// https://godbolt.org/z/hsWrnaEea
namespace {
const int MAX_A = 12; // das Gleiche wie MAX_B, aber kein static nötig
}
static const int MAX_B = 10; // im globalen Namensraum
struct Data {
static const int SIZE = 14; // als Datenfeld in einer Klasse
}
void func() {
static const int LIMIT =16; // als lokale Konstante
}
Godbolt Listing lst-0346-godb.cpp, https://godbolt.org/z/hsWrnaEea:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/hsWrnaEea
namespace {
const int MAX_A = 12; // das Gleiche wie MAX_B, aber kein static nötig
}
static const int MAX_B = 10; // im globalen Namensraum
struct Data {
static const int SIZE = 14; // als Datenfeld in einer Klasse
}
void func() {
static const int LIMIT =16; // als lokale Konstante
}
Listing 13.12: Manche Ausdrücke müssen zur Übersetzungszeit bekannt sein.
Book listing lst-0347-book.cpp:
// https://godbolt.org/z/5b3bvKd9r
#include <array>
int main() {
std::array<int, 5> arr5{}; // Literal und somit ein konstanter Ausdruck
std::array<int, 2+3> arr23{}; // 2+3 kann der Compiler auswerten
const size_t SIZE = 5; // definiert eine Konstante
std::array<int, SIZE> arrSC{}; // kann der Compiler verwenden — oft
size_t size = 7;
std::array<int,size> arrVar{}; // eine Variable können Sie nicht verwenden
}
Godbolt Listing lst-0347-godb.cpp, https://godbolt.org/z/5b3bvKd9r:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/5b3bvKd9r
#include <array>
int main() {
std::array<int, 5> arr5{}; // Literal und somit ein konstanter Ausdruck
std::array<int, 2+3> arr23{}; // 2+3 kann der Compiler auswerten
const size_t SIZE = 5; // definiert eine Konstante
std::array<int, SIZE> arrSC{}; // kann der Compiler verwenden — oft
size_t size = 7;
std::array<int,size> arrVar{}; // eine Variable können Sie nicht verwenden
}
Listing 13.13: Ob der Compiler eine Konstante in einem konstanten Ausdruck verwenden kann, ist nicht immer sofort ersichtlich.
Book listing lst-0348-book.cpp:
// https://godbolt.org/z/MEGfeanPP
#include <array>
struct Data {
static const size_t SPAET; // Konstante deklarieren
static const size_t FRUEH; // Konstante deklarieren
};
void func() {
int x = Data::SPAET; // Konstante verwenden
}
const size_t Data::FRUEH = 10; // Konstante definieren
std::array<int, Data::FRUEH> arrFRUEH {}; // Konstante verwenden
std::array<int, Data::SPAET> arrSPAET {}; // (ERR) Konstante verwenden
const size_t Data::SPAET = 10; // Konstante definieren
int main() {
func();
}
Godbolt Listing lst-0348-godb.cpp, https://godbolt.org/z/MEGfeanPP:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/MEGfeanPP
#include <array>
struct Data {
static const size_t SPAET; // Konstante deklarieren
static const size_t FRUEH; // Konstante deklarieren
};
void func() {
int x = Data::SPAET; // Konstante verwenden
}
const size_t Data::FRUEH = 10; // Konstante definieren
std::array<int, Data::FRUEH> arrFRUEH {}; // Konstante verwenden
std::array<int, Data::SPAET> arrSPAET {}; // (ERR) Konstante verwenden
const size_t Data::SPAET = 10; // Konstante definieren
int main() {
func();
}
Listing 13.14: Mit »constexpr« sieht der Compiler, wann ein Ausdruck nicht früh berechenbar ist.
Book listing lst-0350-book.cpp:
// https://godbolt.org/z/ba9rv6P51
struct Data {
static constexpr size_t SPAET; // (ERR) klappt nicht ohne direkte Initialisierung
static constexpr size_t FRUEH = 10;
};
constexpr size_t Data::SPAET = 10; // (ERR) bei constexpr geht Definition nicht wie bei const
Godbolt Listing lst-0350-godb.cpp, https://godbolt.org/z/ba9rv6P51:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/ba9rv6P51
struct Data {
static constexpr size_t SPAET; // (ERR) klappt nicht ohne direkte Initialisierung
static constexpr size_t FRUEH = 10;
};
constexpr size_t Data::SPAET = 10; // (ERR) bei constexpr geht Definition nicht wie bei const
GodboltId:Krjh8M3aP
Book listing lst-0351-book.cpp:
// https://godbolt.org/z/Krjh8M3aP
constexpr size_t verdoppleWennZuKlein1(size_t wert) {
return wert < 100 ? wert*2 : wert; // liefert das Doppelte zurück, wenn kleiner 100
}
std::array<int, verdoppleWennZuKlein1(50)> arr {};
Godbolt Listing lst-0351-godb.cpp, https://godbolt.org/z/Krjh8M3aP:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Krjh8M3aP
constexpr size_t verdoppleWennZuKlein1(size_t wert) {
return wert < 100 ? wert*2 : wert; // liefert das Doppelte zurück, wenn kleiner 100
}
std::array<int, verdoppleWennZuKlein1(50)> arr {};
GodboltId:KPc6ExMaY
Book listing lst-0352-book.cpp:
// https://godbolt.org/z/KPc6ExMaY
const size_t verdoppleWennZuKlein2(size_t wert) {
return wert < 100 ? wert*2 : wert;
}
std::array<int, verdoppleWennZuKlein2(50)> arr {}; // (ERR) nicht konstant genug
Godbolt Listing lst-0352-godb.cpp, https://godbolt.org/z/KPc6ExMaY:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/KPc6ExMaY
const size_t verdoppleWennZuKlein2(size_t wert) {
return wert < 100 ? wert*2 : wert;
}
std::array<int, verdoppleWennZuKlein2(50)> arr {}; // (ERR) nicht konstant genug
Listing 13.15: Mit »if constexpr« können Sie zur Übersetzungszeit entscheiden, welcher Code ausgeführt wird.
Book listing lst-0354-book.cpp:
// https://godbolt.org/z/zMbnYzo17
template<typename T>
auto deref(T t) {
if constexpr (std::is_pointer_v<T>) {
return *t;
} else {
return t;
}
}
int main() {
int i = 42;
std::cout << deref(i) << '\n'; // direkt der Wert
auto p = std::make_unique<int>(73);
std::cout << deref(p.get()) << '\n'; // dereferenzierter Pointer
}
Godbolt Listing lst-0354-godb.cpp, https://godbolt.org/z/zMbnYzo17:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/zMbnYzo17
template<typename T>
auto deref(T t) {
if constexpr (std::is_pointer_v<T>) {
return *t;
} else {
return t;
}
}
int main() {
int i = 42;
std::cout << deref(i) << '\n'; // direkt der Wert
auto p = std::make_unique<int>(73);
std::cout << deref(p.get()) << '\n'; // dereferenzierter Pointer
}
Listing 13.16: »if constexpr« funktioniert auch mit »else«
Book listing lst-0355-book.cpp:
// https://godbolt.org/z/eo468MvMo
#include <iostream>
#include <string>
struct S {
int n;
std::string s;
float d;
};
template <std::size_t N> auto& get(S& s) {
if constexpr (N == 0) return s.n;
else if constexpr (N == 1) return s.s;
else if constexpr (N == 2) return s.d;
}
int main() {
S obj { 0, "hello", 10.0f };
std::cout << get<0>(obj) << ", " << get<1>(obj) << "\n"; // Ausgabe: 0, hello
}
Godbolt Listing lst-0355-godb.cpp, https://godbolt.org/z/eo468MvMo:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/eo468MvMo
#include <iostream>
#include <string>
struct S {
int n;
std::string s;
float d;
};
template <std::size_t N> auto& get(S& s) {
if constexpr (N == 0) return s.n;
else if constexpr (N == 1) return s.s;
else if constexpr (N == 2) return s.d;
}
int main() {
S obj { 0, "hello", 10.0f };
std::cout << get<0>(obj) << ", " << get<1>(obj) << "\n"; // Ausgabe: 0, hello
}
GodboltId:44KMf1fWr
Book listing lst-0356-book.cpp:
// https://godbolt.org/z/44KMf1fWr
template<auto N>
constexpr auto fibonacci() {
if constexpr (N>=2) {
return fibonacci<N-1>() + fibonacci<N-2>();
} else {
return N;
}
}
int main() {
std::cout << fibonacci<10>() << '\n'; // Ausgabe: 55
std::cout << fibonacci<20>() << '\n'; // Ausgabe: 6765
}
Godbolt Listing lst-0356-godb.cpp, https://godbolt.org/z/44KMf1fWr:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/44KMf1fWr
template<auto N>
constexpr auto fibonacci() {
if constexpr (N>=2) {
return fibonacci<N-1>() + fibonacci<N-2>();
} else {
return N;
}
}
int main() {
std::cout << fibonacci<10>() << '\n'; // Ausgabe: 55
std::cout << fibonacci<20>() << '\n'; // Ausgabe: 6765
}
Listing 13.17: Mit »consteval« können Sie Funktionen zur Übersetzungszeit ausführen lassen.
Book listing lst-0357-book.cpp:
// https://godbolt.org/z/8rr4WKo8d
int hole_eingabe() {
return 50; // oder lese was aus einer Datei oder so
}
constexpr auto berechne_1(int eingabe) {
return eingabe * 2;
}
consteval auto berechne_2(int eingabe) {
return eingabe * 2;
}
int main() {
int eingabe = hole_eingabe();
auto a = berechne_1(77); // zur Übersetzungszeit ... vielleicht berechenbar
auto b = berechne_1(eingabe); // … berechenbar, aber gültig
auto c = berechne_2(77); // … berechenbar
auto d = berechne_2(eingabe); // (ERR) … nicht berechenbar, ungültig
}
Godbolt Listing lst-0357-godb.cpp, https://godbolt.org/z/8rr4WKo8d:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/8rr4WKo8d
int hole_eingabe() {
return 50; // oder lese was aus einer Datei oder so
}
constexpr auto berechne_1(int eingabe) {
return eingabe * 2;
}
consteval auto berechne_2(int eingabe) {
return eingabe * 2;
}
int main() {
int eingabe = hole_eingabe();
auto a = berechne_1(77); // zur Übersetzungszeit ... vielleicht berechenbar
auto b = berechne_1(eingabe); // … berechenbar, aber gültig
auto c = berechne_2(77); // … berechenbar
auto d = berechne_2(eingabe); // (ERR) … nicht berechenbar, ungültig
}
Listing 13.18: Auch komplexere Funktionen können mit »consteval« zur Übersetzungszeit berechnet werden.
Book listing lst-0358-book.cpp:
// https://godbolt.org/z/KGn9ob8on
#include <iostream>
#include <array>
constexpr bool isPrime(int n) { // zur Übersetzungszeit berechenbar
if(n < 2) return false; // 0, 1 sind nicht prim
for (int i = 2; i*i <= n; i += i>2 ? 2 : 1) { // 2,3,5,7,9,11,13,15…
if (n % i == 0) return false;
}
return n > 1; // für 0 und 1
}
template<int Num>
consteval std::array<int, Num> primeNumbers() { // nur zur Übersetzungszeit
std::array<int, Num> primes{};
int idx = 0;
for (int val = 1; idx < Num; ++val) {
if (isPrime(val)) primes[idx++] = val;
}
return primes;
}
int main() {
// Initialisiere mit Primzahlen
auto primes = primeNumbers<100>(); // 1000000 geht nicht
for (auto v : primes) {
std::cout << v << ' ';
}
std::cout << '\n';
}
Godbolt Listing lst-0358-godb.cpp, https://godbolt.org/z/KGn9ob8on:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/KGn9ob8on
#include <iostream>
#include <array>
constexpr bool isPrime(int n) { // zur Übersetzungszeit berechenbar
if(n < 2) return false; // 0, 1 sind nicht prim
for (int i = 2; i*i <= n; i += i>2 ? 2 : 1) { // 2,3,5,7,9,11,13,15…
if (n % i == 0) return false;
}
return n > 1; // für 0 und 1
}
template<int Num>
consteval std::array<int, Num> primeNumbers() { // nur zur Übersetzungszeit
std::array<int, Num> primes{};
int idx = 0;
for (int val = 1; idx < Num; ++val) {
if (isPrime(val)) primes[idx++] = val;
}
return primes;
}
int main() {
// Initialisiere mit Primzahlen
auto primes = primeNumbers<100>(); // 1000000 geht nicht
for (auto v : primes) {
std::cout << v << ' ';
}
std::cout << '\n';
}
Listing 13.19: Der Compiler stellt fest, ob der Aufruf im Context zur Compilezeit berechnet werden kann.
Book listing lst-0359-book.cpp:
// https://godbolt.org/z/7KWqTPo1K
#include <iostream> // cout
constexpr int hole_wert() {
if consteval {
return 42;
} else {
return 668;
}
}
int main() {
auto a = hole_wert();
std::cout << a << '\n'; // Ausgabe: 668
constexpr auto b = hole_wert();
std::cout << b << '\n'; // Ausgabe: 42
}
Godbolt Listing lst-0359-godb.cpp, https://godbolt.org/z/7KWqTPo1K:
//#(compile) c++; compiler:g132; options:"-std=c++23"; libs:-
// https://godbolt.org/z/7KWqTPo1K
#include <iostream> // cout
constexpr int hole_wert() {
if consteval {
return 42;
} else {
return 668;
}
}
int main() {
auto a = hole_wert();
std::cout << a << '\n'; // Ausgabe: 668
constexpr auto b = hole_wert();
std::cout << b << '\n'; // Ausgabe: 42
}
Listing 13.20: »mutable« macht ein Datenfeld in const-Methoden veränderbar.
Book listing lst-0361-book.cpp:
// https://godbolt.org/z/sPorKnEbd
#include <iostream>
class Data {
int value_;
mutable size_t getCount_{0};
public:
explicit Data(int v) : value_{v} { }
~Data() {
std::cout << "get wurde " << getCount_ << "-mal benutzt\n";
}
int get() const {
++getCount_;
return value_;
}
};
int main() {
Data d{42};
for(int i=0; i<10; ++i) { d.get(); }
} // Ausgabe: get wurde 10-mal benutzt
Godbolt Listing lst-0361-godb.cpp, https://godbolt.org/z/sPorKnEbd:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/sPorKnEbd
#include <iostream>
class Data {
int value_;
mutable size_t getCount_{0};
public:
explicit Data(int v) : value_{v} { }
~Data() {
std::cout << "get wurde " << getCount_ << "-mal benutzt\n";
}
int get() const {
++getCount_;
return value_;
}
};
int main() {
Data d{42};
for(int i=0; i<10; ++i) { d.get(); }
} // Ausgabe: get wurde 10-mal benutzt
Listing 13.21: »const« mit Containern
Book listing lst-0362-book.cpp:
// https://godbolt.org/z/GE5v6Ea8x
#include <map>
#include <string>
using std::map; using std::string;
struct MyClass {
bool isFound(const map<int,string> &dict, // unveränderbarer Eingabeparam.
const int &key, // ebenso
string &result // Ausgabeparameter: kein const
) const // Instanz von MyClass const
{
const map<int,string>::const_iterator where // Verweis und Wert fest
= dict.find(key);
if(where == end(dict)) {
return false;
} else {
result = where->second;
return true;
}
}
};
Godbolt Listing lst-0362-godb.cpp, https://godbolt.org/z/GE5v6Ea8x:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/GE5v6Ea8x
#include <map>
#include <string>
using std::map; using std::string;
struct MyClass {
bool isFound(const map<int,string> &dict, // unveränderbarer Eingabeparam.
const int &key, // ebenso
string &result // Ausgabeparameter: kein const
) const // Instanz von MyClass const
{
const map<int,string>::const_iterator where // Verweis und Wert fest
= dict.find(key);
if(where == end(dict)) {
return false;
} else {
result = where->second;
return true;
}
}
};
Listing 13.22: x und y können irgendwie von außen verändert werden.
Book listing lst-0363-book.cpp:
#include <iostream>
#include <chrono> // milliseconds
#include <thread> // this_thread::sleep
struct Pos {
volatile int x;
volatile int y;
};
Pos pos{};
// irgendwo anders definiert:
int installMouseDriver(Pos *p);
constexpr auto DELAY = std::chrono::milliseconds(100);
constexpr auto LOOPS = 30; // 30*100ms = 3s
int main() {
installMouseDriver( &pos ); // MouseDriver aktualisiert x und y
for(int i=0; i<LOOPS; ++i) {
std::cout << "maus bei ("<<pos.x<<","<<pos.y<<")\n";
std::this_thread::sleep_for(DELAY);
}
}
Listing 14.1: Solitäre Tests testen nur eine Komponente, Helferklassen werden untergeschoben.
Book listing lst-0364-book.cpp:
// https://godbolt.org/z/a83sf9h8E
#include <iostream>
// Produktionscode:
struct DatabaseInterface {
virtual int getData() const = 0;
};
struct Programm {
DatabaseInterface &db_;
void run() {
std:: cout << db_.getData() << "\n";
}
};
// Testhelfer:
struct MockDatabase : public DatabaseInterface {
int getData() const override { return 5; }
};
// main als Test:
int main() {
MockDatabase mockDb;
Programm prog { mockDb }; // echte DB wird nicht mitgetestet
prog.run(); // Erwartete Ausgabe: 5
}
Godbolt Listing lst-0364-godb.cpp, https://godbolt.org/z/a83sf9h8E:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/a83sf9h8E
#include <iostream>
// Produktionscode:
struct DatabaseInterface {
virtual int getData() const = 0;
};
struct Programm {
DatabaseInterface &db_;
void run() {
std:: cout << db_.getData() << "\n";
}
};
// Testhelfer:
struct MockDatabase : public DatabaseInterface {
int getData() const override { return 5; }
};
// main als Test:
int main() {
MockDatabase mockDb;
Programm prog { mockDb }; // echte DB wird nicht mitgetestet
prog.run(); // Erwartete Ausgabe: 5
}
Listing 14.2: Soziale Tests testen das Zusammenspiel der Komponenten mit.
Book listing lst-0365-book.cpp:
// https://godbolt.org/z/fsroE4seh
#include <iostream>
// Produktionscode:
struct DatabaseInterface {
virtual int getData() const = 0;
};
struct RealDatabase : public DatabaseInterface {
int getData() const override { return 999; }
};
struct Programm {
DatabaseInterface &db_;
void run() {
std:: cout << db_.getData() << "\n";
}
};
// main als Test:
int main() {
RealDatabase db;
Programm prog { db }; // echte DB wird mitgetestet
prog.run(); // Erwartete Ausgabe: 999
}
Godbolt Listing lst-0365-godb.cpp, https://godbolt.org/z/fsroE4seh:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/fsroE4seh
#include <iostream>
// Produktionscode:
struct DatabaseInterface {
virtual int getData() const = 0;
};
struct RealDatabase : public DatabaseInterface {
int getData() const override { return 999; }
};
struct Programm {
DatabaseInterface &db_;
void run() {
std:: cout << db_.getData() << "\n";
}
};
// main als Test:
int main() {
RealDatabase db;
Programm prog { db }; // echte DB wird mitgetestet
prog.run(); // Erwartete Ausgabe: 999
}
GodboltId:4PeYrc8jo
Book listing lst-0366-book.cpp:
// https://godbolt.org/z/4PeYrc8jo
void testVerdopple5() {
// vorbereiten
auto param = 5;
// ausführen
auto result = verdopple(param);
// überprüfen
assertTrue(result == 10);
}
Godbolt Listing lst-0366-godb.cpp, https://godbolt.org/z/4PeYrc8jo:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/4PeYrc8jo
void testVerdopple5() {
// vorbereiten
auto param = 5;
// ausführen
auto result = verdopple(param);
// überprüfen
assertTrue(result == 10);
}
GodboltId:Y9exe7rqT
Book listing lst-0367-book.cpp:
// https://godbolt.org/z/Y9exe7rqT
void testVerdopple() {
assertTrue( verdopple(0) == 0 );
assertTrue( verdopple(-1) == -2 );
assertTrue( verdopple(1) == 2 );
assertTrue( verdopple(5) == 10 );
}
Godbolt Listing lst-0367-godb.cpp, https://godbolt.org/z/Y9exe7rqT:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Y9exe7rqT
void testVerdopple() {
assertTrue( verdopple(0) == 0 );
assertTrue( verdopple(-1) == -2 );
assertTrue( verdopple(1) == 2 );
assertTrue( verdopple(5) == 10 );
}
Listing 14.3: In der Datei »fib.cpp« ist eine freie Funktion, die Sie testen wollen.
Book listing lst-0368-book.cpp:
// https://godbolt.org/z/Ex6Mv6xcz
unsigned fib(unsigned n) {
if(n==0) { return 0; }
if(n==1) { return 1; }
unsigned a = 0;
unsigned b = 1;
unsigned sum = 1;
while(n>1) {
sum += a;
a = b;
b = sum;
n -= 1;
}
return sum;
}
Godbolt Listing lst-0368-godb.cpp, https://godbolt.org/z/Ex6Mv6xcz:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Ex6Mv6xcz
unsigned fib(unsigned n) {
if(n==0) { return 0; }
if(n==1) { return 1; }
unsigned a = 0;
unsigned b = 1;
unsigned sum = 1;
while(n>1) {
sum += a;
a = b;
b = sum;
n -= 1;
}
return sum;
}
GodboltId:ba7e7s8qK
Book listing lst-0369-book.cpp:
// https://godbolt.org/z/ba7e7s8qK
#define BOOST_TEST_MAIN test_main // generiert main() in diesem Modul
#include <boost/test/included/unit_test.hpp> // Framework
#include <boost/test/test_tools.hpp> // BOOST_CHECK etc
unsigned fib(unsigned n); // zu testen
namespace {
using namespace boost::unit_test;
BOOST_AUTO_TEST_CASE( test_fib_low ) // beliebiger Name des Testcases
{
BOOST_CHECK( fib(0) == 0 ); // einzelne Assertions
BOOST_CHECK( fib(1) == 1 );
BOOST_CHECK( fib(2) == 1 );
BOOST_CHECK( fib(3) == 2 );
BOOST_CHECK( fib(4) == 3 );
BOOST_CHECK( fib(5) == 5 );
BOOST_CHECK( fib(6) == 8 );
}
}
Godbolt Listing lst-0369-godb.cpp, https://godbolt.org/z/ba7e7s8qK:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/ba7e7s8qK
#define BOOST_TEST_MAIN test_main // generiert main() in diesem Modul
#include <boost/test/included/unit_test.hpp> // Framework
#include <boost/test/test_tools.hpp> // BOOST_CHECK etc
unsigned fib(unsigned n); // zu testen
namespace {
using namespace boost::unit_test;
BOOST_AUTO_TEST_CASE( test_fib_low ) // beliebiger Name des Testcases
{
BOOST_CHECK( fib(0) == 0 ); // einzelne Assertions
BOOST_CHECK( fib(1) == 1 );
BOOST_CHECK( fib(2) == 1 );
BOOST_CHECK( fib(3) == 2 );
BOOST_CHECK( fib(4) == 3 );
BOOST_CHECK( fib(5) == 5 );
BOOST_CHECK( fib(6) == 8 );
}
}
Listing 14.4: Die Haupt-Headerdatei der Bibliothek qwort.hpp
Book listing lst-0375-book.cpp:
// https://godbolt.org/z/5ajrvGvcW
#ifndef QWORT_H // Header-Guard
#define QWORT_H
#include <string>
#include <string_view>
#include <memory> // unique_ptr
namespace qw { // Namensraum der Bibliothek
int version();
namespace impl_multimap {
class index_impl;
}
class index {
using index_impl = impl_multimap::index_impl;
public:
index();
~index() noexcept; // wird für pimpl benötigt
index(const index&) = delete;
index(index&&) noexcept;
index& operator=(const index&) = delete;
index& operator=(index&&) = delete;
public:
void add(std::string_view arg);
size_t size() const;
std::string getBestMatch(std::string_view query) const;
public: // public für Tests
std::string normalize(std::string arg) const;
private:
std::unique_ptr<index_impl> pimpl;
};
} // namespace qw
#endif // Header-Guard
Godbolt Listing lst-0375-godb.cpp, https://godbolt.org/z/5ajrvGvcW:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/5ajrvGvcW
#ifndef QWORT_H // Header-Guard
#define QWORT_H
#include <string>
#include <string_view>
#include <memory> // unique_ptr
namespace qw { // Namensraum der Bibliothek
int version();
namespace impl_multimap {
class index_impl;
}
class index {
using index_impl = impl_multimap::index_impl;
public:
index();
~index() noexcept; // wird für pimpl benötigt
index(const index&) = delete;
index(index&&) noexcept;
index& operator=(const index&) = delete;
index& operator=(index&&) = delete;
public:
void add(std::string_view arg);
size_t size() const;
std::string getBestMatch(std::string_view query) const;
public: // public für Tests
std::string normalize(std::string arg) const;
private:
std::unique_ptr<index_impl> pimpl;
};
} // namespace qw
#endif // Header-Guard
Listing 14.5: Öffentliche Schnittstelle nur fürs Testen
Book listing lst-0376-book.cpp:
class index_impl {
// ...
public: // test interface
vector<string> _qgramify(string_view n) const { return qgramify(n); }
static size_t _q() { return Q; }
static std::string _prefix() { return PREFIX; }
static std::string _suffix() { return SUFFIX; }
};
Listing 14.6: Dieses Testmodul testet qwort.cpp.
Book listing lst-0377-book.cpp:
// https://godbolt.org/z/Y98jq1eGx
#include "qwort/qwort.hpp" // under test
#define BOOST_TEST_MODULE qwort
#include <boost/test/included/unit_test.hpp>
using namespace boost::unit_test;
BOOST_AUTO_TEST_CASE( version_is_1 ) {
BOOST_TEST(qw::version() == 1);
// der folgende Vergleich soll fehlschlagen, aber nur eine Warnung erzeugen:
BOOST_WARN_EQUAL(qw::version(), 2); // (ERR) ungleich, aber macht weiter
}
BOOST_AUTO_TEST_CASE( init_size_0 ) {
qw::index inst{}; // arrange
auto sz = inst.size(); // act
BOOST_TEST(sz == 0u); // assert
}
BOOST_AUTO_TEST_CASE( add_size_1 ) {
using namespace std::literals::string_literals;
qw::index inst{}; // arrange
inst.add(""s); // act
BOOST_REQUIRE_EQUAL(inst.size(), 1u); // assert
}
BOOST_AUTO_TEST_CASE( normalize ) {
using namespace std::literals::string_literals;
qw::index inst{}; // arrange
// acts und asserts; könnte auch in getrennten Funktionen sein
BOOST_CHECK_EQUAL(inst.normalize("a"s), "A"s);
BOOST_CHECK_EQUAL(inst.normalize("Stadt"s), "STADT"s);
BOOST_CHECK_EQUAL(inst.normalize("Leer Zeichen"s), "LEER#ZEICHEN"s);
BOOST_CHECK_EQUAL(inst.normalize("!Sym-bol."s), "#SYM#BOL#"s);
}
BOOST_AUTO_TEST_CASE( move ) {
qw::index inst{};
qw::index other = std::move( inst );
BOOST_CHECK_EQUAL(other.size(), 0u); // pimpl erfolgreich verschoben?
}
Godbolt Listing lst-0377-godb.cpp, https://godbolt.org/z/Y98jq1eGx:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Y98jq1eGx
#include "qwort/qwort.hpp" // under test
#define BOOST_TEST_MODULE qwort
#include <boost/test/included/unit_test.hpp>
using namespace boost::unit_test;
BOOST_AUTO_TEST_CASE( version_is_1 ) {
BOOST_TEST(qw::version() == 1);
// der folgende Vergleich soll fehlschlagen, aber nur eine Warnung erzeugen:
BOOST_WARN_EQUAL(qw::version(), 2); // (ERR) ungleich, aber macht weiter
}
BOOST_AUTO_TEST_CASE( init_size_0 ) {
qw::index inst{}; // arrange
auto sz = inst.size(); // act
BOOST_TEST(sz == 0u); // assert
}
BOOST_AUTO_TEST_CASE( add_size_1 ) {
using namespace std::literals::string_literals;
qw::index inst{}; // arrange
inst.add(""s); // act
BOOST_REQUIRE_EQUAL(inst.size(), 1u); // assert
}
BOOST_AUTO_TEST_CASE( normalize ) {
using namespace std::literals::string_literals;
qw::index inst{}; // arrange
// acts und asserts; könnte auch in getrennten Funktionen sein
BOOST_CHECK_EQUAL(inst.normalize("a"s), "A"s);
BOOST_CHECK_EQUAL(inst.normalize("Stadt"s), "STADT"s);
BOOST_CHECK_EQUAL(inst.normalize("Leer Zeichen"s), "LEER#ZEICHEN"s);
BOOST_CHECK_EQUAL(inst.normalize("!Sym-bol."s), "#SYM#BOL#"s);
}
BOOST_AUTO_TEST_CASE( move ) {
qw::index inst{};
qw::index other = std::move( inst );
BOOST_CHECK_EQUAL(other.size(), 0u); // pimpl erfolgreich verschoben?
}
Listing 14.7: Hier wird die Testsuite manuell zusammengebaut.
Book listing lst-0387-book.cpp:
// https://godbolt.org/z/TfMnK1Tnn
/* private Header aus lib-Verzeichnis: */
#include "impl_multimap.hpp" // zu testen
// wir definieren init_unit_test_suite() selbst, also NICHT setzen:
/* #define BOOST_TEST_MODULE qgram */
#include <boost/test/included/unit_test.hpp>
#include <memory> // shared ptr
#include <vector>
#include <string>
using namespace boost::unit_test;
using namespace std::literals::string_literals;
using std::string; using std::vector;
/* === Eine Testklasse für die zu testende Klasse === */
using UnderTest = qw::impl_multimap::index_impl;
class ImplMultimapTest { // Klasse mit Testmethoden
public:
/* === Konstanten === */
void testConstants() {
BOOST_REQUIRE_EQUAL(UnderTest::_prefix().length(), UnderTest::_q()-1);
BOOST_REQUIRE_EQUAL(UnderTest::_suffix().length(), UnderTest::_q()-1);
for(size_t i = 0; i < UnderTest::_q()-1; ++i) {
BOOST_CHECK_EQUAL(UnderTest::_prefix()[i], '^');
BOOST_CHECK_EQUAL(UnderTest::_suffix()[i], '$');
}
// oder konkreter:
BOOST_TEST(UnderTest::_q() == 3u);
BOOST_TEST(UnderTest::_prefix() == "^^"s);
BOOST_TEST(UnderTest::_suffix() == "$$"s);
}
/* === qgramify === */
void testQgramifyEmpty() {
UnderTest inst{};
auto result = inst._qgramify(""s);
vector<string> expected{"^^$"s, "^$$"s};
BOOST_CHECK_EQUAL_COLLECTIONS(
result.begin(), result.end(), expected.begin(), expected.end() );
}
void testQgramify1() {
UnderTest inst{};
auto result = inst._qgramify("a"s);
vector<string> expected{"^^a"s, "^a$"s, "a$$"s};
BOOST_CHECK_EQUAL_COLLECTIONS(
result.begin(), result.end(), expected.begin(), expected.end() );
}
void testQgramify2() {
UnderTest inst{};
auto result = inst._qgramify("ab"s);
vector<string> expected{"^^a"s, "^ab"s, "ab$"s, "b$$"s};
BOOST_CHECK_EQUAL_COLLECTIONS(
result.begin(), result.end(), expected.begin(), expected.end() );
}
void testQgramify3() {
UnderTest inst{};
auto result = inst._qgramify("abc"s);
vector<string> expected{"^^a"s, "^ab"s, "abc"s, "bc$"s, "c$$"s};
BOOST_CHECK_EQUAL_COLLECTIONS(
result.begin(), result.end(), expected.begin(), expected.end() );
}
/* === add === */
void testAdd_nodups() {
UnderTest inst{}; /* arrange */
BOOST_REQUIRE_EQUAL(inst.size(), 0u); /* assert */
inst.add("", ""); /* act */
BOOST_CHECK_EQUAL(inst.size(), 1u); /* assert */
inst.add("ENTRY", "entry"); /* act */
BOOST_CHECK_EQUAL(inst.size(), 2u); /* assert */
inst.add("OTHER", "other"); /* act */
BOOST_CHECK_EQUAL(inst.size(), 3u); /* assert */
}
/* === add === */
void test_getBestMatch_empty() {
UnderTest inst{};
auto result = inst.getBestMatch("any");
BOOST_CHECK_EQUAL(result, ""s);
}
void test_getBestMatch_one() {
/* arrange */
UnderTest inst{};
inst.add("HOLSDERTEUFEL", "holsderteufel");
/* act */
auto result = inst.getBestMatch("ROBERT");
BOOST_CHECK_EQUAL(result, "holsderteufel"s);
}
void test_getBestMatch_exact() {
/* arrange */
UnderTest inst{};
inst.add("BERLIN", "Berlin");
inst.add("HAMBURG", "Hamburg");
inst.add("DORTMUND", "Dortmund");
inst.add("STUTTGART", "Stuttgart");
inst.add("WYK", "Wyk");
/* act and assert */
BOOST_CHECK_EQUAL(inst.getBestMatch("BERLIN"), "Berlin"s);
BOOST_CHECK_EQUAL(inst.getBestMatch("HAMBURG"), "Hamburg"s);
BOOST_CHECK_EQUAL(inst.getBestMatch("DORTMUND"), "Dortmund"s);
BOOST_CHECK_EQUAL(inst.getBestMatch("STUTTGART"), "Stuttgart"s);
BOOST_CHECK_EQUAL(inst.getBestMatch("WYK"), "Wyk"s);
}
void test_getBestMatch_close() {
/* arrange */
UnderTest inst{};
inst.add("BERLIN", "Berlin");
inst.add("HAMBURG", "Hamburg");
inst.add("DORTMUND", "Dortmund");
inst.add("STUTTGART", "Stuttgart");
inst.add("WYK", "Wyk");
/* act and assert */
BOOST_CHECK_EQUAL(inst.getBestMatch("BRLIN"), "Berlin"s);
BOOST_CHECK_EQUAL(inst.getBestMatch("BURG"), "Hamburg"s);
BOOST_CHECK_EQUAL(inst.getBestMatch("DORTDORT"), "Dortmund"s);
BOOST_CHECK_EQUAL(inst.getBestMatch("STUTGURT"), "Stuttgart"s);
BOOST_CHECK_EQUAL(inst.getBestMatch("WIK"), "Wyk"s);
}
/* Bei neuen Testmethoden: Hinzufügen zu init_unit_test_suite() nicht vergessen */
};
/* === Suite === */
test_suite* init_unit_test_suite( int argc, char* argv[] ) {
auto tester = std::make_shared<ImplMultimapTest>();
auto &ts = framework::master_test_suite();
ts.add( BOOST_TEST_CASE( [=](){ tester->testConstants(); } ));
ts.add( BOOST_TEST_CASE( [=](){ tester->testQgramifyEmpty(); } ));
ts.add( BOOST_TEST_CASE( [=](){ tester->testQgramify1(); } ));
ts.add( BOOST_TEST_CASE( [=](){ tester->testQgramify2(); } ));
ts.add( BOOST_TEST_CASE( [=](){ tester->testQgramify3(); } ));
ts.add( BOOST_TEST_CASE( [=](){ tester->testQgramify3(); } ));
ts.add( BOOST_TEST_CASE( [=](){ tester->testAdd_nodups(); } ));
ts.add( BOOST_TEST_CASE( [=](){ tester->test_getBestMatch_empty(); } ));
ts.add( BOOST_TEST_CASE( [=](){ tester->test_getBestMatch_one(); } ));
ts.add( BOOST_TEST_CASE( [=](){ tester->test_getBestMatch_exact(); } ));
ts.add( BOOST_TEST_CASE( [=](){ tester->test_getBestMatch_close(); } ));
return nullptr;
}
Godbolt Listing lst-0387-godb.cpp, https://godbolt.org/z/TfMnK1Tnn:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/TfMnK1Tnn
/* private Header aus lib-Verzeichnis: */
#include "impl_multimap.hpp" // zu testen
// wir definieren init_unit_test_suite() selbst, also NICHT setzen:
/* #define BOOST_TEST_MODULE qgram */
#include <boost/test/included/unit_test.hpp>
#include <memory> // shared ptr
#include <vector>
#include <string>
using namespace boost::unit_test;
using namespace std::literals::string_literals;
using std::string; using std::vector;
/* === Eine Testklasse für die zu testende Klasse === */
using UnderTest = qw::impl_multimap::index_impl;
class ImplMultimapTest { // Klasse mit Testmethoden
public:
/* === Konstanten === */
void testConstants() {
BOOST_REQUIRE_EQUAL(UnderTest::_prefix().length(), UnderTest::_q()-1);
BOOST_REQUIRE_EQUAL(UnderTest::_suffix().length(), UnderTest::_q()-1);
for(size_t i = 0; i < UnderTest::_q()-1; ++i) {
BOOST_CHECK_EQUAL(UnderTest::_prefix()[i], '^');
BOOST_CHECK_EQUAL(UnderTest::_suffix()[i], '$');
}
// oder konkreter:
BOOST_TEST(UnderTest::_q() == 3u);
BOOST_TEST(UnderTest::_prefix() == "^^"s);
BOOST_TEST(UnderTest::_suffix() == "$$"s);
}
/* === qgramify === */
void testQgramifyEmpty() {
UnderTest inst{};
auto result = inst._qgramify(""s);
vector<string> expected{"^^$"s, "^$$"s};
BOOST_CHECK_EQUAL_COLLECTIONS(
result.begin(), result.end(), expected.begin(), expected.end() );
}
void testQgramify1() {
UnderTest inst{};
auto result = inst._qgramify("a"s);
vector<string> expected{"^^a"s, "^a$"s, "a$$"s};
BOOST_CHECK_EQUAL_COLLECTIONS(
result.begin(), result.end(), expected.begin(), expected.end() );
}
void testQgramify2() {
UnderTest inst{};
auto result = inst._qgramify("ab"s);
vector<string> expected{"^^a"s, "^ab"s, "ab$"s, "b$$"s};
BOOST_CHECK_EQUAL_COLLECTIONS(
result.begin(), result.end(), expected.begin(), expected.end() );
}
void testQgramify3() {
UnderTest inst{};
auto result = inst._qgramify("abc"s);
vector<string> expected{"^^a"s, "^ab"s, "abc"s, "bc$"s, "c$$"s};
BOOST_CHECK_EQUAL_COLLECTIONS(
result.begin(), result.end(), expected.begin(), expected.end() );
}
/* === add === */
void testAdd_nodups() {
UnderTest inst{}; /* arrange */
BOOST_REQUIRE_EQUAL(inst.size(), 0u); /* assert */
inst.add("", ""); /* act */
BOOST_CHECK_EQUAL(inst.size(), 1u); /* assert */
inst.add("ENTRY", "entry"); /* act */
BOOST_CHECK_EQUAL(inst.size(), 2u); /* assert */
inst.add("OTHER", "other"); /* act */
BOOST_CHECK_EQUAL(inst.size(), 3u); /* assert */
}
/* === add === */
void test_getBestMatch_empty() {
UnderTest inst{};
auto result = inst.getBestMatch("any");
BOOST_CHECK_EQUAL(result, ""s);
}
void test_getBestMatch_one() {
/* arrange */
UnderTest inst{};
inst.add("HOLSDERTEUFEL", "holsderteufel");
/* act */
auto result = inst.getBestMatch("ROBERT");
BOOST_CHECK_EQUAL(result, "holsderteufel"s);
}
void test_getBestMatch_exact() {
/* arrange */
UnderTest inst{};
inst.add("BERLIN", "Berlin");
inst.add("HAMBURG", "Hamburg");
inst.add("DORTMUND", "Dortmund");
inst.add("STUTTGART", "Stuttgart");
inst.add("WYK", "Wyk");
/* act and assert */
BOOST_CHECK_EQUAL(inst.getBestMatch("BERLIN"), "Berlin"s);
BOOST_CHECK_EQUAL(inst.getBestMatch("HAMBURG"), "Hamburg"s);
BOOST_CHECK_EQUAL(inst.getBestMatch("DORTMUND"), "Dortmund"s);
BOOST_CHECK_EQUAL(inst.getBestMatch("STUTTGART"), "Stuttgart"s);
BOOST_CHECK_EQUAL(inst.getBestMatch("WYK"), "Wyk"s);
}
void test_getBestMatch_close() {
/* arrange */
UnderTest inst{};
inst.add("BERLIN", "Berlin");
inst.add("HAMBURG", "Hamburg");
inst.add("DORTMUND", "Dortmund");
inst.add("STUTTGART", "Stuttgart");
inst.add("WYK", "Wyk");
/* act and assert */
BOOST_CHECK_EQUAL(inst.getBestMatch("BRLIN"), "Berlin"s);
BOOST_CHECK_EQUAL(inst.getBestMatch("BURG"), "Hamburg"s);
BOOST_CHECK_EQUAL(inst.getBestMatch("DORTDORT"), "Dortmund"s);
BOOST_CHECK_EQUAL(inst.getBestMatch("STUTGURT"), "Stuttgart"s);
BOOST_CHECK_EQUAL(inst.getBestMatch("WIK"), "Wyk"s);
}
/* Bei neuen Testmethoden: Hinzufügen zu init_unit_test_suite() nicht vergessen */
};
/* === Suite === */
test_suite* init_unit_test_suite( int argc, char* argv[] ) {
auto tester = std::make_shared<ImplMultimapTest>();
auto &ts = framework::master_test_suite();
ts.add( BOOST_TEST_CASE( [=](){ tester->testConstants(); } ));
ts.add( BOOST_TEST_CASE( [=](){ tester->testQgramifyEmpty(); } ));
ts.add( BOOST_TEST_CASE( [=](){ tester->testQgramify1(); } ));
ts.add( BOOST_TEST_CASE( [=](){ tester->testQgramify2(); } ));
ts.add( BOOST_TEST_CASE( [=](){ tester->testQgramify3(); } ));
ts.add( BOOST_TEST_CASE( [=](){ tester->testQgramify3(); } ));
ts.add( BOOST_TEST_CASE( [=](){ tester->testAdd_nodups(); } ));
ts.add( BOOST_TEST_CASE( [=](){ tester->test_getBestMatch_empty(); } ));
ts.add( BOOST_TEST_CASE( [=](){ tester->test_getBestMatch_one(); } ));
ts.add( BOOST_TEST_CASE( [=](){ tester->test_getBestMatch_exact(); } ));
ts.add( BOOST_TEST_CASE( [=](){ tester->test_getBestMatch_close(); } ));
return nullptr;
}
Listing 14.8: Eine Testfunktion mit einem Parameter kann mit Testdaten aufgerufen werden.
Book listing lst-0392-book.cpp:
// https://godbolt.org/z/q8E6WMano
#include <boost/test/parameterized_test.hpp>
struct Param {
string input;
vector<string> expected;
};
const vector<Param> params {
// { Eingabe, erwartetes Ergebnis }
{""s, {"^^$"s, "^$$"s} },
{"A"s, {"^^A"s, "^A$"s, "A$$"s} },
{"AB"s, {"^^A"s, "^AB"s, "AB$"s, "B$$"s} },
{"ACB"s, {"^^A"s, "^AC"s, "ACB"s, "CB$"s, "B$$"s} },
{"AAA"s, {"^^A"s, "^AA"s, "AAA"s, "AA$"s, "A$$"s} },
};
void testQgramify(const Param& param) {
/* arrange */
UnderTest inst{};
/* act */
auto result = inst._qgramify(param.input);
/* assert */
BOOST_CHECK_EQUAL_COLLECTIONS(
param.expected.begin(), param.expected.end(),
result.begin(), result.end());
}
Godbolt Listing lst-0392-godb.cpp, https://godbolt.org/z/q8E6WMano:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/q8E6WMano
#include <boost/test/parameterized_test.hpp>
struct Param {
string input;
vector<string> expected;
};
const vector<Param> params {
// { Eingabe, erwartetes Ergebnis }
{""s, {"^^$"s, "^$$"s} },
{"A"s, {"^^A"s, "^A$"s, "A$$"s} },
{"AB"s, {"^^A"s, "^AB"s, "AB$"s, "B$$"s} },
{"ACB"s, {"^^A"s, "^AC"s, "ACB"s, "CB$"s, "B$$"s} },
{"AAA"s, {"^^A"s, "^AA"s, "AAA"s, "AA$"s, "A$$"s} },
};
void testQgramify(const Param& param) {
/* arrange */
UnderTest inst{};
/* act */
auto result = inst._qgramify(param.input);
/* assert */
BOOST_CHECK_EQUAL_COLLECTIONS(
param.expected.begin(), param.expected.end(),
result.begin(), result.end());
}
Listing 15.1: Der gemeinsame Vorfahre unserer Hilfsklassen »Year«, »Month« und »Day«
Book listing lst-0398-book.cpp:
// https://godbolt.org/z/hhGo46z5a
#include <iostream> // ostream
#include <format> // format, vformat, make_format_args
using std::ostream;
class Value {
protected: // nicht öffentlich, nur für den eigenen und abgeleiteten Gebrauch
int value_;
const std::string fmt_; // z. B. "{:02}" oder "{:04}"
Value(int v, unsigned w) // Konstruktor mit zwei Argumenten
: value_{v}, fmt_{std::format("{{:0{}}}", w)} {}
public:
ostream& print(ostream& os) const;
};
ostream& operator<<(ostream& os, const Value& rechts) {
return rechts.print(os);
}
ostream& Value::print(ostream& os) const {
return os << std::vformat(fmt_, std::make_format_args(value_));
}
Godbolt Listing lst-0398-godb.cpp, https://godbolt.org/z/hhGo46z5a:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/hhGo46z5a
#include <iostream> // ostream
#include <format> // format, vformat, make_format_args
using std::ostream;
class Value {
protected: // nicht öffentlich, nur für den eigenen und abgeleiteten Gebrauch
int value_;
const std::string fmt_; // z. B. "{:02}" oder "{:04}"
Value(int v, unsigned w) // Konstruktor mit zwei Argumenten
: value_{v}, fmt_{std::format("{{:0{}}}", w)} {}
public:
ostream& print(ostream& os) const;
};
ostream& operator<<(ostream& os, const Value& rechts) {
return rechts.print(os);
}
ostream& Value::print(ostream& os) const {
return os << std::vformat(fmt_, std::make_format_args(value_));
}
Listing 15.2: Der doppelte Code der Hilfsklassen ist nun verschwunden.
Book listing lst-0399-book.cpp:
// https://godbolt.org/z/eYY1js4Te
class Year : public Value { // von Klasse Value ableiten
public:
explicit Year(int v) : Value{v, 4} {} // Basisklasse initialisieren
};
class Month : public Value {
public:
explicit Month(int v) : Value{v, 2} {}
};
struct Day : public Value { // class-public entspricht struct
explicit Day(int v) : Value{v, 2} {}
};
Godbolt Listing lst-0399-godb.cpp, https://godbolt.org/z/eYY1js4Te:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/eYY1js4Te
class Year : public Value { // von Klasse Value ableiten
public:
explicit Year(int v) : Value{v, 4} {} // Basisklasse initialisieren
};
class Month : public Value {
public:
explicit Month(int v) : Value{v, 2} {}
};
struct Day : public Value { // class-public entspricht struct
explicit Day(int v) : Value{v, 2} {}
};
Listing 15.3: So verwendet »Date« die neuen Klassen.
Book listing lst-0400-book.cpp:
// https://godbolt.org/z/9rY7qhK89
class Date {
Year year_;
Month month_ {1};
Day day_ {1};
public:
explicit Date(int y) : year_{y} {} // year-01-01
Date(Year y, Month m, Day d) : year_{y}, month_{m}, day_{d} {}
ostream& print(ostream& os) const;
};
ostream& Date::print(ostream& os) const {
return os << year_ << "-" << month_ << "-" << day_;
}
ostream& operator<<(ostream& os, const Date& rechts) {
return rechts.print(os);
}
int main() {
Date d1 { Year{2013}, Month{15}, Day{19} };
std::cout << d1 << "\n"; // Ausgabe: 2013-15-19
}
Godbolt Listing lst-0400-godb.cpp, https://godbolt.org/z/9rY7qhK89:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/9rY7qhK89
class Date {
Year year_;
Month month_ {1};
Day day_ {1};
public:
explicit Date(int y) : year_{y} {} // year-01-01
Date(Year y, Month m, Day d) : year_{y}, month_{m}, day_{d} {}
ostream& print(ostream& os) const;
};
ostream& Date::print(ostream& os) const {
return os << year_ << "-" << month_ << "-" << day_;
}
ostream& operator<<(ostream& os, const Date& rechts) {
return rechts.print(os);
}
int main() {
Date d1 { Year{2013}, Month{15}, Day{19} };
std::cout << d1 << "\n"; // Ausgabe: 2013-15-19
}
Listing 15.4: Nun ist »ostern« eine Methode von »Year«.
Book listing lst-0401-book.cpp:
// https://godbolt.org/z/Wjsvv6Gdv
class Date; // Vorwärtsdeklaration
class Year : public Value {
public:
explicit Year(int v) : Value{v, 4} {}
Date ostern() const; // neue Methode deklarieren
};
// Hier Month, Day und Date deklarieren. Dann:
Date Year::ostern() const { // neue Methode definieren
const int y = value_;
int a = value_/100*1483 - value_/400*2225 + 2613;
int b = (value_%19*3510 + a/25*319)/330%29;
b = 148 - b - (value_*5/4 + a - b)%7;
return Date{Year{value_}, Month{b/31}, Day{b%31 + 1}};
}
int main() {
using std::cout;
Year year{2014};
cout << year.ostern() << "\n"; // Ausgabe: 2014-04-20
}
Godbolt Listing lst-0401-godb.cpp, https://godbolt.org/z/Wjsvv6Gdv:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Wjsvv6Gdv
class Date; // Vorwärtsdeklaration
class Year : public Value {
public:
explicit Year(int v) : Value{v, 4} {}
Date ostern() const; // neue Methode deklarieren
};
// Hier Month, Day und Date deklarieren. Dann:
Date Year::ostern() const { // neue Methode definieren
const int y = value_;
int a = value_/100*1483 - value_/400*2225 + 2613;
int b = (value_%19*3510 + a/25*319)/330%29;
b = 148 - b - (value_*5/4 + a - b)%7;
return Date{Year{value_}, Month{b/31}, Day{b%31 + 1}};
}
int main() {
using std::cout;
Year year{2014};
cout << year.ostern() << "\n"; // Ausgabe: 2014-04-20
}
Listing 15.5: Alle Komponenten haben eine weiße Farbe, nur der Druckknopf wird grau.
Book listing lst-0402-book.cpp:
struct Komponente {
Color getColor() const { return weiss; }
};
struct Fenster : public Komponente { };
struct Hauptfenster : public Fenster { };
struct Dialog : public Fenster { };
struct Texteingabe : public Komponente { };
struct Druckknopf : public Komponente {
Color getColor() const { return grau; }
};
Listing 15.6: Was gibt »print« aus? Die Methode »wert« kommt öfter vor.
Book listing lst-0403-book.cpp:
// https://godbolt.org/z/476G1xzKr
#include <iostream>
struct Basis {
int acht_ = 8;
int wert() const { return acht_; }
void print(std::ostream& os) const { os << wert() << "\n"; }
};
struct Print : public Basis {
int neun_ = 9;
void print(std::ostream& os) const { os << wert() << "\n"; }
};
struct Wert : public Basis {
int zehn_ = 10;
int wert() const { return zehn_; }
};
struct Beides : public Basis {
int elf_ = 11;
int wert() const { return elf_; }
void print(std::ostream& os) const { os << wert() << "\n"; }
};
int main() {
Basis ba{}; ba.print(std::cout); // Basisaufruf
Print pr{}; pr.print(std::cout); // print überschrieben
Wert we{}; we.print(std::cout); // print aus Basis
Beides be{}; be.print(std::cout); // alles überschrieben
}
Godbolt Listing lst-0403-godb.cpp, https://godbolt.org/z/476G1xzKr:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/476G1xzKr
#include <iostream>
struct Basis {
int acht_ = 8;
int wert() const { return acht_; }
void print(std::ostream& os) const { os << wert() << "\n"; }
};
struct Print : public Basis {
int neun_ = 9;
void print(std::ostream& os) const { os << wert() << "\n"; }
};
struct Wert : public Basis {
int zehn_ = 10;
int wert() const { return zehn_; }
};
struct Beides : public Basis {
int elf_ = 11;
int wert() const { return elf_; }
void print(std::ostream& os) const { os << wert() << "\n"; }
};
int main() {
Basis ba{}; ba.print(std::cout); // Basisaufruf
Print pr{}; pr.print(std::cout); // print überschrieben
Wert we{}; we.print(std::cout); // print aus Basis
Beides be{}; be.print(std::cout); // alles überschrieben
}
Listing 15.7: Mit »virtual« markierte Methoden werden zur Laufzeit aufgelöst.
Book listing lst-0404-book.cpp:
// https://godbolt.org/z/aj8cnox4f
#include <iostream>
using std::ostream; using std::cout;
struct Basis2 {
int acht_ = 8;
virtual int wert() const // virtuelle Methode
{ return acht_; }
void print(ostream& os) const
{ os << wert() << "\n"; }
};
struct Wert2 : public Basis2 {
int zehn_ = 10;
virtual int wert() const override // überschreiben
{ return zehn_; }
};
int main() {
Wert2 we2{}; we2.print(cout); // verwenden
}
Godbolt Listing lst-0404-godb.cpp, https://godbolt.org/z/aj8cnox4f:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/aj8cnox4f
#include <iostream>
using std::ostream; using std::cout;
struct Basis2 {
int acht_ = 8;
virtual int wert() const // virtuelle Methode
{ return acht_; }
void print(ostream& os) const
{ os << wert() << "\n"; }
};
struct Wert2 : public Basis2 {
int zehn_ = 10;
virtual int wert() const override // überschreiben
{ return zehn_; }
};
int main() {
Wert2 we2{}; we2.print(cout); // verwenden
}
Listing 15.8: Die abgeleitete Klasse erbt Methoden, aber nicht Konstruktoren der Elternklasse.
Book listing lst-0406-book.cpp:
// https://godbolt.org/z/57vexTPnn
class Base {
public:
Base() {} // null-Argument-Konstruktor
explicit Base(int i) {} // ein Argument
Base(int i, int j) {} // zwei Argumente
void func() {}; // Methode
};
class Derived : public Base { // kein eigener Konstruktor
};
int main() {
Base b0{}; // okay, null-Argument-Konstruktor
Base b1{12}; // okay, ein Argument
Base b2{6,18}; // okay, zwei Argumente
Derived d0{}; // okay, Compiler generiert Defaultkonstruktor
d0.func(); // okay, Methode wird geerbt
Derived d1{7}; // (ERR) Fehler: kein Konstruktor für ein Argument
Derived d2{3,13}; // (ERR) Fehler: kein Konstruktor für zwei Argumente
}
Godbolt Listing lst-0406-godb.cpp, https://godbolt.org/z/57vexTPnn:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/57vexTPnn
class Base {
public:
Base() {} // null-Argument-Konstruktor
explicit Base(int i) {} // ein Argument
Base(int i, int j) {} // zwei Argumente
void func() {}; // Methode
};
class Derived : public Base { // kein eigener Konstruktor
};
int main() {
Base b0{}; // okay, null-Argument-Konstruktor
Base b1{12}; // okay, ein Argument
Base b2{6,18}; // okay, zwei Argumente
Derived d0{}; // okay, Compiler generiert Defaultkonstruktor
d0.func(); // okay, Methode wird geerbt
Derived d1{7}; // (ERR) Fehler: kein Konstruktor für ein Argument
Derived d2{3,13}; // (ERR) Fehler: kein Konstruktor für zwei Argumente
}
Listing 15.9: Mit »using« importieren Sie alle Konstruktoren der Elternklasse.
Book listing lst-0407-book.cpp:
// https://godbolt.org/z/8b3Yvnjh4
class Base {
public:
Base() {}
explicit Base(int i) {}
Base(int i, int j) {}
void func() {}; // Methode
};
class Derived : public Base {
public:
using Base::Base; // Importieren aller Konstruktoren der Elternklasse
};
int main() {
Derived d0{}; // okay, importiert, nicht mehr generiert
Derived d1{7}; // okay, wurde importiert
Derived d2{3,13}; // okay, wurde importiert
}
Godbolt Listing lst-0407-godb.cpp, https://godbolt.org/z/8b3Yvnjh4:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/8b3Yvnjh4
class Base {
public:
Base() {}
explicit Base(int i) {}
Base(int i, int j) {}
void func() {}; // Methode
};
class Derived : public Base {
public:
using Base::Base; // Importieren aller Konstruktoren der Elternklasse
};
int main() {
Derived d0{}; // okay, importiert, nicht mehr generiert
Derived d1{7}; // okay, wurde importiert
Derived d2{3,13}; // okay, wurde importiert
}
Listing 15.10: Die Übergabe als Wert kopiert nur den gemeinsamen Teil des Typs.
Book listing lst-0408-book.cpp:
// https://godbolt.org/z/jfocr7qf1
//… Basis2 und Wert2 wie gehabt …
void ausgabe(Basis2 x) { // Übergabe als Wert
x.print(cout);
}
int main() {
Basis2 ba2{}; ausgabe(ba2); // gibt 8 aus
Wert2 we2{}; ausgabe(we2); // gibt auch 8 aus
}
Godbolt Listing lst-0408-godb.cpp, https://godbolt.org/z/jfocr7qf1:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/jfocr7qf1
//… Basis2 und Wert2 wie gehabt …
void ausgabe(Basis2 x) { // Übergabe als Wert
x.print(cout);
}
int main() {
Basis2 ba2{}; ausgabe(ba2); // gibt 8 aus
Wert2 we2{}; ausgabe(we2); // gibt auch 8 aus
}
Listing 15.11: Die abgeleitete Klasse als Argumenttyp zu einer Funktion erlaubt nicht den Aufruf mit einer Variable der Basisklasse als Wertparameter.
Book listing lst-0409-book.cpp:
// https://godbolt.org/z/j9Er3s1xo
//… Basis2 und Wert2 wie gehabt …
void ausgabe(Wert2 x) { // abgeleitete Klasse als Wert
x.print(cout);
}
int main() {
Basis2 ba2{}; ausgabe(ba2); // (ERR) ba2 kann nicht in Wert2 umgewandelt werden
Wert2 we2{}; ausgabe(we2); // gibt 10 aus
}
Godbolt Listing lst-0409-godb.cpp, https://godbolt.org/z/j9Er3s1xo:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/j9Er3s1xo
//… Basis2 und Wert2 wie gehabt …
void ausgabe(Wert2 x) { // abgeleitete Klasse als Wert
x.print(cout);
}
int main() {
Basis2 ba2{}; ausgabe(ba2); // (ERR) ba2 kann nicht in Wert2 umgewandelt werden
Wert2 we2{}; ausgabe(we2); // gibt 10 aus
}
Listing 15.12: Die Übergabe als Referenz verändert die Instanz nicht.
Book listing lst-0410-book.cpp:
// https://godbolt.org/z/3nvrvrrYW
//… Basis2 und Wert2 wie gehabt …
void ausgabe(Basis2& x) { // Übergabe als Referenz
x.print(cout);
}
int main() {
Basis2 ba2{}; ausgabe(ba2); // gibt 8 aus
Wert2 we2{}; ausgabe(we2); // gibt 10 aus, denn das Objekt wird nicht kopiert
}
Godbolt Listing lst-0410-godb.cpp, https://godbolt.org/z/3nvrvrrYW:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/3nvrvrrYW
//… Basis2 und Wert2 wie gehabt …
void ausgabe(Basis2& x) { // Übergabe als Referenz
x.print(cout);
}
int main() {
Basis2 ba2{}; ausgabe(ba2); // gibt 8 aus
Wert2 we2{}; ausgabe(we2); // gibt 10 aus, denn das Objekt wird nicht kopiert
}
Listing 16.1: Welche Variablen können Sie bei »x1« bis »x5« einsetzen?
Book listing lst-0411-book.cpp:
// https://godbolt.org/z/K7TqWrjbo
struct MeinWert { /* irgendwas */ };
MeinWert globalWert{}; // globale Klasseninstanz
void funktion(const MeinWert ¶mRef) {
if( /*...*/ ) funktion( /*x1?*/ ); // irgendeine Funktion aufrufen
MeinWert lokalWert{}; // lokale Klasseninstanz
} // Ende der Funktion
int main() {
MeinWert mwert1{};
funktion( /*x2?*/ );
funktion( MeinWert{} ); // temporärer Wert
{
MeinWert mwert2{};
funktion( /*x3?*/ );
MeinWert mwert3{};
} // Ende des inneren Blocks
funktion( /*x4?*/ );
MeinWert mwert4{};
funktion( /*x5?*/ );
} // Ende der main-Funktion
Godbolt Listing lst-0411-godb.cpp, https://godbolt.org/z/K7TqWrjbo:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/K7TqWrjbo
struct MeinWert { /* irgendwas */ };
MeinWert globalWert{}; // globale Klasseninstanz
void funktion(const MeinWert ¶mRef) {
if( /*...*/ ) funktion( /*x1?*/ ); // irgendeine Funktion aufrufen
MeinWert lokalWert{}; // lokale Klasseninstanz
} // Ende der Funktion
int main() {
MeinWert mwert1{};
funktion( /*x2?*/ );
funktion( MeinWert{} ); // temporärer Wert
{
MeinWert mwert2{};
funktion( /*x3?*/ );
MeinWert mwert3{};
} // Ende des inneren Blocks
funktion( /*x4?*/ );
MeinWert mwert4{};
funktion( /*x5?*/ );
} // Ende der main-Funktion
Listing 16.2: Wenn Sie eine Funktion mit einem Parameter aufrufen, für den der Compiler zur Umwandlung einen Konstruktor aufruft, erzeugt er einen Tempwert.
Book listing lst-0412-book.cpp:
// https://godbolt.org/z/TvKP7Ghvh
#include <string>
#include <iostream> // cout
using std::string; using std::cout;
struct Value {
int wert_;
Value(int wert) // 1-Arg-Konstruktor = Typumwandlung
: wert_{wert} {}
};
size_t laenge(string arg) {
return arg.size();
}
Value doppel(Value v) {
return Value{ v.wert_*2 };
}
int main() {
cout << laenge("Hipphopp") << "\n"; // const char* in string
cout << doppel(10).wert_ << "\n"; // int in Value
string name {"Gandalf"};
cout << ( name + " der Graue" ) << "\n"; // string + const char*
}
Godbolt Listing lst-0412-godb.cpp, https://godbolt.org/z/TvKP7Ghvh:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/TvKP7Ghvh
#include <string>
#include <iostream> // cout
using std::string; using std::cout;
struct Value {
int wert_;
Value(int wert) // 1-Arg-Konstruktor = Typumwandlung
: wert_{wert} {}
};
size_t laenge(string arg) {
return arg.size();
}
Value doppel(Value v) {
return Value{ v.wert_*2 };
}
int main() {
cout << laenge("Hipphopp") << "\n"; // const char* in string
cout << doppel(10).wert_ << "\n"; // int in Value
string name {"Gandalf"};
cout << ( name + " der Graue" ) << "\n"; // string + const char*
}
Listing 16.3: Ein Destruktor wird beim Entfernen eines Objekts ausgeführt.
Book listing lst-0413-book.cpp:
// https://godbolt.org/z/qzbnK9v1o
#include <string>
#include <iostream>
#include <iomanip> // setw
using std::cout; using std::setw; using std::string;
struct MeinWert {
static int zaehler; // static: existiert nur einmal für alle Instanzen
int nummer_; // Einrücktiefe dieser Instanz für die Ausgabe
string name_; // Name dieser Instanz für die Ausgabe
explicit MeinWert(string name)
: nummer_{++zaehler} // Zähler für Einrücktiefe pro Instanz hochzählen
, name_{name} // Name des Objekts für Ausgabe merken
{
cout << setw(nummer_) << " " // nummer_ verwenden für Einrücktiefe
<< "Konstruktor " << name_ << "\n"; // Instanzname ausgeben }
~MeinWert() { // Destruktor
cout << setw(nummer_) << " " << "Destruktor " << name_ << "\n";
}
};
int MeinWert::zaehler = 0; // Initialisierung der statischen Klassenvariablen
Godbolt Listing lst-0413-godb.cpp, https://godbolt.org/z/qzbnK9v1o:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/qzbnK9v1o
#include <string>
#include <iostream>
#include <iomanip> // setw
using std::cout; using std::setw; using std::string;
struct MeinWert {
static int zaehler; // static: existiert nur einmal für alle Instanzen
int nummer_; // Einrücktiefe dieser Instanz für die Ausgabe
string name_; // Name dieser Instanz für die Ausgabe
explicit MeinWert(string name)
: nummer_{++zaehler} // Zähler für Einrücktiefe pro Instanz hochzählen
, name_{name} // Name des Objekts für Ausgabe merken
{
cout << setw(nummer_) << " " // nummer_ verwenden für Einrücktiefe
<< "Konstruktor " << name_ << "\n"; // Instanzname ausgeben }
~MeinWert() { // Destruktor
cout << setw(nummer_) << " " << "Destruktor " << name_ << "\n";
}
};
int MeinWert::zaehler = 0; // Initialisierung der statischen Klassenvariablen
Listing 16.4: Hier werden viele Objekte erzeugt und zerstört.
Book listing lst-0414-book.cpp:
// https://godbolt.org/z/oY953arPj
void funktion(const MeinWert ¶mRef) {
MeinWert lokalWert{"lokal"};
}
int main() {
MeinWert mwert1{"mwert1"};
funktion( MeinWert{"temp"} );
funktion( mwert1 );
{
MeinWert mwert2{"mwert2"};
}
}
Godbolt Listing lst-0414-godb.cpp, https://godbolt.org/z/oY953arPj:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/oY953arPj
void funktion(const MeinWert ¶mRef) {
MeinWert lokalWert{"lokal"};
}
int main() {
MeinWert mwert1{"mwert1"};
funktion( MeinWert{"temp"} );
funktion( mwert1 );
{
MeinWert mwert2{"mwert2"};
}
}
Listing 16.5: Diese Ausgabe zeigt, wann Objekte erzeugt und zerstört werden.
Book listing lst-0415-book.cpp:
Konstruktor mwert1
Konstruktor temp
Konstruktor lokal
Destruktor lokal
Destruktor temp
Konstruktor lokal
Destruktor lokal
Konstruktor mwert2
Destruktor mwert2
Destruktor mwert1
Listing 16.6: Ein einfaches Beispiel für eine C-Schnittstelle zu einer Ressource
Book listing lst-0416-book.cpp:
// https://godbolt.org/z/54dzsb31z
#ifndef DATABASE_HPP
#define DATABASE_HPP
typedef void* db_handle_t;
db_handle_t db_open(const char* filename);
void db_close(db_handle_t db);
int db_execute(db_handle_t db, const char* query);
#endif
Godbolt Listing lst-0416-godb.cpp, https://godbolt.org/z/54dzsb31z:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/54dzsb31z
#ifndef DATABASE_HPP
#define DATABASE_HPP
typedef void* db_handle_t;
db_handle_t db_open(const char* filename);
void db_close(db_handle_t db);
int db_execute(db_handle_t db, const char* query);
#endif
Listing 16.7: Wenn Sie eine Ressource schließen müssen, dann eignet sich dafür der Destruktor.
Book listing lst-0417-book.cpp:
// https://godbolt.org/z/93PT8W9hY
#include <iostream> // cout
#include "database.hpp" // Einbinden der fremden Programmierschnittstelle
class Database {
db_handle_t db_; // eingepackte Ressource
public:
Database(const char* filename);
~Database();
int execute(const char* query);
};
Database::Database(const char* filename)
: db_{db_open(filename)} // Anfordern der Ressource
{ }
Database::~Database() {
db_close(db_); // Freigeben der Ressource
}
int Database::execute(const char* query) {
return db_execute(db_, query); // Nutzen der Ressource
}
int main() {
Database db{ "kunden.dat" }; // Erzeugen des Wrappers
std::cout << "Anzahl: "<< db.execute("select * from kunden") << "\n";
} // automatisches Entfernen des Wrappers
Godbolt Listing lst-0417-godb.cpp, https://godbolt.org/z/93PT8W9hY:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/93PT8W9hY
#include <iostream> // cout
#include "database.hpp" // Einbinden der fremden Programmierschnittstelle
class Database {
db_handle_t db_; // eingepackte Ressource
public:
Database(const char* filename);
~Database();
int execute(const char* query);
};
Database::Database(const char* filename)
: db_{db_open(filename)} // Anfordern der Ressource
{ }
Database::~Database() {
db_close(db_); // Freigeben der Ressource
}
int Database::execute(const char* query) {
return db_execute(db_, query); // Nutzen der Ressource
}
int main() {
Database db{ "kunden.dat" }; // Erzeugen des Wrappers
std::cout << "Anzahl: "<< db.execute("select * from kunden") << "\n";
} // automatisches Entfernen des Wrappers
Listing 16.8: Der Konstruktor initialisiert oder löst eine Exception aus.
Book listing lst-0418-book.cpp:
Database::Database(const char* filename)
: db_{ db_open(filename) }
{
if(nullptr == db_) { // Fehler beim Öffnen
throw IllegalArgumentException("Fehler beim Oeffnen der DB");
}
}
Listing 16.9: Beispiele für Yoda-Bedingungen mit »==«
Book listing lst-0420-book.cpp:
if("Yoda" == character) …
if(42 == antwort) …
Listing 16.10: Eine Yoda-Bedingung mit einem Methodenaufruf
Book listing lst-0421-book.cpp:
// https://godbolt.org/z/c3695v4r8
#include "mein_string.hpp"
static const mein_string ZEBRA { "zebra" };
int main() {
mein_string tier{ "pferd" };
if(ZEBRA.equals(tier)) return 0;
else return 1;
}
Godbolt Listing lst-0421-godb.cpp, https://godbolt.org/z/c3695v4r8:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/c3695v4r8
#include "mein_string.hpp"
static const mein_string ZEBRA { "zebra" };
int main() {
mein_string tier{ "pferd" };
if(ZEBRA.equals(tier)) return 0;
else return 1;
}
Listing 16.11: Der Konstruktor von »KannWerfen« kann mit einer Exception beendet werden.
Book listing lst-0422-book.cpp:
// https://godbolt.org/z/vaP4bdvns
#include <iostream> // cout
#include <stdexcept> // runtime_error
struct KannWerfen {
KannWerfen(int wasSollPassieren) {
std::cout << "Konstruktor " << wasSollPassieren << "...\n";
if(wasSollPassieren == 666)
throw std::runtime_error("Testfehler");
std::cout << "...Konstruktor fertig\n";
}
~KannWerfen() {
std::cout << "Destruktor.\n";
}
};
int main() {
try {
KannWerfen kw1{0}; // okay, löst keine Ausnahme aus
} catch(std::runtime_error &exc) {
std::cout << "Gefangen-1: " << exc.what() << "\n";
}
try {
KannWerfen kw2{666}; // löst aus, kw2 wird nicht erzeugt
} catch(std::runtime_error &exc) {
std::cout << "Gefangen-2: " << exc.what() << "\n";
}
}
Godbolt Listing lst-0422-godb.cpp, https://godbolt.org/z/vaP4bdvns:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/vaP4bdvns
#include <iostream> // cout
#include <stdexcept> // runtime_error
struct KannWerfen {
KannWerfen(int wasSollPassieren) {
std::cout << "Konstruktor " << wasSollPassieren << "...\n";
if(wasSollPassieren == 666)
throw std::runtime_error("Testfehler");
std::cout << "...Konstruktor fertig\n";
}
~KannWerfen() {
std::cout << "Destruktor.\n";
}
};
int main() {
try {
KannWerfen kw1{0}; // okay, löst keine Ausnahme aus
} catch(std::runtime_error &exc) {
std::cout << "Gefangen-1: " << exc.what() << "\n";
}
try {
KannWerfen kw2{666}; // löst aus, kw2 wird nicht erzeugt
} catch(std::runtime_error &exc) {
std::cout << "Gefangen-2: " << exc.what() << "\n";
}
}
Listing 16.12: Teilweise initialisierte Datenfelder werden auch bei einer Exception weggeräumt.
Book listing lst-0423-book.cpp:
class Mega {
std::vector<int> data_;
KannWerfen kannWerfen_;
std::map<string,int> mehr_;
public:
Mega()
: data_{}
, kannWerfen_{666} // löst eine Exception aus
, mehr_{}
{ }
};
Listing 16.13: Die Übergabe als Wert erstellt Objekte mit dem vom Compiler erzeugten Kopierkonstruktor.
Book listing lst-0424-book.cpp:
// https://godbolt.org/z/KGEe7hj1b
void funktion(MeinWert paramWert) {
std::cout << "(funktion)\n";
MeinWert lokalWert{"lokal"};
}
int main() {
MeinWert mwert1{"mwert1"};
funktion( MeinWert{"temp"} );
funktion( mwert1 );
{
MeinWert mwert2{"mwert2"};
}
}
Godbolt Listing lst-0424-godb.cpp, https://godbolt.org/z/KGEe7hj1b:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/KGEe7hj1b
void funktion(MeinWert paramWert) {
std::cout << "(funktion)\n";
MeinWert lokalWert{"lokal"};
}
int main() {
MeinWert mwert1{"mwert1"};
funktion( MeinWert{"temp"} );
funktion( mwert1 );
{
MeinWert mwert2{"mwert2"};
}
}
Listing 16.14: Der Kopierkonstruktor bekommt eine konstante Referenz der Klasse als Argument.
Book listing lst-0425-book.cpp:
// https://godbolt.org/z/j67W4zPWE
struct MeinWert {
static int zaehler;
int nummer_;
string name_;
explicit MeinWert(string name) // wie zuvor
: nummer_{++zaehler} , name_{name}
{ cout << setw(nummer_) << '_' << "Konstruktor " << name_ << "\n"; }
MeinWert(const MeinWert &orig) // neuer Kopierkonstruktor
: nummer_{++zaehler} , name_{orig.name_ + "-Kopie"}
{ cout << setw(nummer_)<<" " << "Kopierkonstruktor " << name_ << "\n"; }
~MeinWert() { // wie zuvor
cout << setw(nummer_)<<" " << "Destruktor " << name_ << "\n";
}
};
int MeinWert::zaehler = 0;
Godbolt Listing lst-0425-godb.cpp, https://godbolt.org/z/j67W4zPWE:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/j67W4zPWE
struct MeinWert {
static int zaehler;
int nummer_;
string name_;
explicit MeinWert(string name) // wie zuvor
: nummer_{++zaehler} , name_{name}
{ cout << setw(nummer_) << '_' << "Konstruktor " << name_ << "\n"; }
MeinWert(const MeinWert &orig) // neuer Kopierkonstruktor
: nummer_{++zaehler} , name_{orig.name_ + "-Kopie"}
{ cout << setw(nummer_)<<" " << "Kopierkonstruktor " << name_ << "\n"; }
~MeinWert() { // wie zuvor
cout << setw(nummer_)<<" " << "Destruktor " << name_ << "\n";
}
};
int MeinWert::zaehler = 0;
Listing 16.15: Kopie und Zuweisung
Book listing lst-0426-book.cpp:
void byVal(MeinWert arg) { }
int main() {
MeinWert wert1{"ABCD"}; // neue Instanz, konstruiert per string
MeinWert wert2{wert1}; // neue Instanz, konstruiert per Kopie
MeinWert wert3 = wert1; // neue Instanz, ebenfalls per Kopie, trotz =
byVal(wert1); // eine neue Instanz per Kopie
wert1 = wert2; // keine neue Instanz, sondern eine Zuweisung
}
Listing 16.16: Das Schema für die Implementierung eines eigenen Zuweisungsoperators
Book listing lst-0429-book.cpp:
struct MeinWert {
// … alles andere wie bisher
MeinWert& operator=(const MeinWert& rechts) {
if(this != &rechts) { // 1. auf Selbstzuweisung prüfen
// 2. Freigeben bisheriger Ressourcen; hier keine
// 3. elementweises Übertragen durch Zuweisung oder Ähnliches
name_ = rechts.name_ + "-Zuweisung (zuvor " + name_ + ")";
/* nummer_ bleibt, und damit die originale Einrückung */
}
return *this; // 4. sich selbst zurückgeben
}
};
Listing 16.17: »const«-Datenelement zunächst ohne Zuweisungsoperator
Book listing lst-0430-book.cpp:
struct MeineNummer {
const int nummer_; // konstantes Datenfeld
explicit MeineNummer(int v)
: nummer_{v} // Initialisierung des konstanten Datenfelds
{}
};
int main() {
MeineNummer c1{4};
MeineNummer c2{7};
c1 = c2; // (ERR) Fehler: Zuweisung vom Compiler gestrichen
}
Listing 16.18: Mit »= delete« entfernen Sie Operationen manuell.
Book listing lst-0431-book.cpp:
// https://godbolt.org/z/acWjozE15
struct MeineNummer {
int nummer_; // variables Datenfeld
explicit MeineNummer(int v)
: nummer_{v} {}
MeineNummer& operator=(const MeineNummer&) = delete; // Zuweisung streichen
MeineNummer(const MeineNummer&) = delete; // Kopie streichen
};
int main() {
MeineNummer c1{4};
MeineNummer c2{7};
c1 = c2; // (ERR) Fehler – Zuweisung vom Programmierer gestrichen
MeineNummer c3{c1}; // (ERR) Fehler – Kopie vom Programmierer gestrichen
}
Godbolt Listing lst-0431-godb.cpp, https://godbolt.org/z/acWjozE15:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/acWjozE15
struct MeineNummer {
int nummer_; // variables Datenfeld
explicit MeineNummer(int v)
: nummer_{v} {}
MeineNummer& operator=(const MeineNummer&) = delete; // Zuweisung streichen
MeineNummer(const MeineNummer&) = delete; // Kopie streichen
};
int main() {
MeineNummer c1{4};
MeineNummer c2{7};
c1 = c2; // (ERR) Fehler – Zuweisung vom Programmierer gestrichen
MeineNummer c3{c1}; // (ERR) Fehler – Kopie vom Programmierer gestrichen
}
Listing 16.19: Mit den gelöschten Funktionen verhindert der Compiler eine fehlerhafte Benutzung der Klasse.
Book listing lst-0432-book.cpp:
// https://godbolt.org/z/PfW8oKPK4
#include <iostream> // cout
#include "database.hpp" // Einbinden der fremden Programmierschnittstelle
class Database {
const db_handle_t db_; // konstant machen
public:
Database(const char* filename);
~Database();
int execute(const char* query);
Database(const Database&) = delete; // Kopieren verbieten
Database& operator=(const Database&) = delete; // Zuweisung verbieten
};
// … Implementierungen wie gehabt …
int main() {
Database db{ "kunden.dat" };
std::cout << "Anzahl: "<< db.execute("select * from kunden") << "\n";
Database db2{ db }; // (ERR) Compiler verhindert gefährliche Kopie
db = db2; // (ERR) Compiler verhindert gefährliche Zuweisung
}
Godbolt Listing lst-0432-godb.cpp, https://godbolt.org/z/PfW8oKPK4:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/PfW8oKPK4
#include <iostream> // cout
#include "database.hpp" // Einbinden der fremden Programmierschnittstelle
class Database {
const db_handle_t db_; // konstant machen
public:
Database(const char* filename);
~Database();
int execute(const char* query);
Database(const Database&) = delete; // Kopieren verbieten
Database& operator=(const Database&) = delete; // Zuweisung verbieten
};
// … Implementierungen wie gehabt …
int main() {
Database db{ "kunden.dat" };
std::cout << "Anzahl: "<< db.execute("select * from kunden") << "\n";
Database db2{ db }; // (ERR) Compiler verhindert gefährliche Kopie
db = db2; // (ERR) Compiler verhindert gefährliche Zuweisung
}
Listing 16.20: Die Klasse enthält wahrscheinlich große Datenmengen, die teuer zu kopieren sind. Doch was wird hier kopiert?
Book listing lst-0433-book.cpp:
// https://godbolt.org/z/MT3MPs3rE
#include <vector>
class Image {
std::vector<std::byte> data_;
public:
explicit Image(const char *fn) { /*...*/ }
// Compiler generiert (u. a.):
// Kopierkonstruktor, Zuweisung, aber auch Verschiebungen
};
std::vector<Image> loadCollection(bool empty) {
if(empty) return std::vector<Image>{};
std::vector<Image> result {}; // für Rückgabe; zunächst leer
// drei Bilder in die Sammlung … kopieren?
result.push_back( Image{"MonaLisa.png"} );
result.push_back( Image{"DerSchrei.png"} );
result.push_back( Image{"JungeMitPfeife.png"} );
return result; // Sammlung als Wert zurückgeben
}
int main() {
// Rückgabe in Variable speichern
std::vector<Image> sammlung = loadCollection(false);
}
Godbolt Listing lst-0433-godb.cpp, https://godbolt.org/z/MT3MPs3rE:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/MT3MPs3rE
#include <vector>
class Image {
std::vector<std::byte> data_;
public:
explicit Image(const char *fn) { /*...*/ }
// Compiler generiert (u. a.):
// Kopierkonstruktor, Zuweisung, aber auch Verschiebungen
};
std::vector<Image> loadCollection(bool empty) {
if(empty) return std::vector<Image>{};
std::vector<Image> result {}; // für Rückgabe; zunächst leer
// drei Bilder in die Sammlung … kopieren?
result.push_back( Image{"MonaLisa.png"} );
result.push_back( Image{"DerSchrei.png"} );
result.push_back( Image{"JungeMitPfeife.png"} );
return result; // Sammlung als Wert zurückgeben
}
int main() {
// Rückgabe in Variable speichern
std::vector<Image> sammlung = loadCollection(false);
}
Listing 16.21: Implementierung der beiden Verschiebeoperationen
Book listing lst-0434-book.cpp:
// https://godbolt.org/z/6xjeYWe7c
#include <vector>
class Image {
std::vector<std::byte> data_; // byte gibt es seit C++17
public:
explicit Image(const char *fn) { /*...*/ }
Image(Image&& other) noexcept // Verschiebekonstruktor
: data_{} // leer erzeugen
{
using std::swap;
swap(data_, other.data_);
}
Image& operator=(Image&& other) noexcept { // Verschiebeoperator
using std::swap;
swap(data_, other.data_);
return *this;
}
};
Godbolt Listing lst-0434-godb.cpp, https://godbolt.org/z/6xjeYWe7c:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/6xjeYWe7c
#include <vector>
class Image {
std::vector<std::byte> data_; // byte gibt es seit C++17
public:
explicit Image(const char *fn) { /*...*/ }
Image(Image&& other) noexcept // Verschiebekonstruktor
: data_{} // leer erzeugen
{
using std::swap;
swap(data_, other.data_);
}
Image& operator=(Image&& other) noexcept { // Verschiebeoperator
using std::swap;
swap(data_, other.data_);
return *this;
}
};
Listing 16.22: Infix-, Funktions- und Methodenschreibweise für Operatoren
Book listing lst-0440-book.cpp:
// https://godbolt.org/z/fefP5d343
#include <iostream>
using std::cout; using std::ostream;
struct Widget {
bool operator<(const Widget&) const { // Methodenschreibweise
return true; // immer true
}
};
bool operator<(const Widget&, const Widget&) { // Funktionsschreibweise
return false; // immer false
}
int main() {
Widget x{};
Widget y{};
cout << (operator<(x, y) // ruft Funktionsschreibweise auf
? "Methode1\n" : "Funktion1\n");
cout << (y.operator<(x) // ruft Methodenschreibweise auf
? "Methode2\n" : "Funktion2\n");
cout << (x < y // Infix-Schreibweise, lässt die Wahl, hier Methode
? "Methode3\n" : "Funktion3\n");
}
Godbolt Listing lst-0440-godb.cpp, https://godbolt.org/z/fefP5d343:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/fefP5d343
#include <iostream>
using std::cout; using std::ostream;
struct Widget {
bool operator<(const Widget&) const { // Methodenschreibweise
return true; // immer true
}
};
bool operator<(const Widget&, const Widget&) { // Funktionsschreibweise
return false; // immer false
}
int main() {
Widget x{};
Widget y{};
cout << (operator<(x, y) // ruft Funktionsschreibweise auf
? "Methode1\n" : "Funktion1\n");
cout << (y.operator<(x) // ruft Methodenschreibweise auf
? "Methode2\n" : "Funktion2\n");
cout << (x < y // Infix-Schreibweise, lässt die Wahl, hier Methode
? "Methode3\n" : "Funktion3\n");
}
Listing 16.23: Eine »friend«-Funktion ist keine Methode, auch wenn sie innerhalb der Klasse steht oder dort definiert ist.
Book listing lst-0441-book.cpp:
// https://godbolt.org/z/Wvr3aK75G
#include <compare> // für <=>
class Value {
// Wenn Sie class verwenden, geht es mit Privatem los.
int value_;
public:
explicit Value(int value) : value_{value} {}
// freie Funktionen, aber als friend deklariert
friend Value operator+(const Value& li, const Value& re);
friend Value operator-(const Value& li, const Value& re)
{ return Value{li.value_ - re.value_}; // innerhalb auch definiert
}
// operator<=> braucht nicht friend zu sein.
// für alle Vergleiche: <, >, <=, >= sowie == und !=
auto operator<=>(const Value& re) const = default;
};
// Definition der zuvor deklarierten friend-Funktion:
Value operator+(const Value& li, const Value& re) {
return Value{li.value_ + re.value_}; // Zugriff auf Privates erlaubt
}
int main() {
Value sieben{7}; Value drei{3}; Value zwei{2};
if((drei+zwei) < sieben) { // operator+, dann operarator< via <=>
return 0; // okay
} else {
return 1; // etwas ist falsch gelaufen
}
}
Godbolt Listing lst-0441-godb.cpp, https://godbolt.org/z/Wvr3aK75G:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Wvr3aK75G
#include <compare> // für <=>
class Value {
// Wenn Sie class verwenden, geht es mit Privatem los.
int value_;
public:
explicit Value(int value) : value_{value} {}
// freie Funktionen, aber als friend deklariert
friend Value operator+(const Value& li, const Value& re);
friend Value operator-(const Value& li, const Value& re)
{ return Value{li.value_ - re.value_}; // innerhalb auch definiert
}
// operator<=> braucht nicht friend zu sein.
// für alle Vergleiche: <, >, <=, >= sowie == und !=
auto operator<=>(const Value& re) const = default;
};
// Definition der zuvor deklarierten friend-Funktion:
Value operator+(const Value& li, const Value& re) {
return Value{li.value_ + re.value_}; // Zugriff auf Privates erlaubt
}
int main() {
Value sieben{7}; Value drei{3}; Value zwei{2};
if((drei+zwei) < sieben) { // operator+, dann operarator< via <=>
return 0; // okay
} else {
return 1; // etwas ist falsch gelaufen
}
}
Listing 16.24: Ein beinahe mit allen Operatoren voll ausgerüsteter Datentyp
Book listing lst-0442-book.cpp:
// https://godbolt.org/z/Gf38nTa1q
#include <iostream> // istream, ostream, cout
class Num {
int val_ = 0;
public:
int& operator*(); // Dereferenzieren: Zugriff auf den Wert direkt erhalten
const int& operator*() const; // Dereferenzieren: Lesezugriff auf den Wert
Num() {}
explicit Num(int value) : val_{value} {}
// einstellige Operatoren
Num& operator++(); // Pre-Inkrement
Num& operator--(); // Pre-Dekrement
Num operator+(); // Positiv
Num operator-(); // Negieren
Num operator~(); // bitweises Invertieren
// zweistellige Operatoren
// - zusammengesetzte Zuweisungen, arithmetisch
Num& operator+=(const Num& re) { val_ += *re; return *this; }
Num& operator-=(const Num& re) { val_ -= *re; return *this; }
Num& operator*=(const Num& re) { val_ *= *re; return *this; }
Num& operator/=(const Num& re) { val_ /= *re; return *this; }
Num& operator%=(const Num& re) { val_ %= *re; return *this; }
// - zusammengesetzte Zuweisungen, bitweise
Num& operator|=(const Num& re) { val_ |= *re; return *this; }
Num& operator&=(const Num& re) { val_ &= *re; return *this; }
Num& operator^=(const Num& re) { val_ ^= *re; return *this; }
Num& operator<<=(int n) { val_ <<= n; return *this; }
Num& operator>>=(int n) { val_ >>= n; return *this; }
// - Variation zusammengesetzter Zuweisungen, für einfachere Bedienung
Num& operator+=(int re) { val_ += re; return *this; }
Num& operator-=(int re) { val_ -= re; return *this; }
// zweistellige Operatoren, mit Call-by-Value für den ersten Parameter
// und die die zusammengesetzte Zuweisung zu Hilfe nehmen
// - Arithmetik
friend Num operator+(Num li, const Num& re) { return li += re; }
friend Num operator-(Num li, const Num& re) { return li -= re; }
friend Num operator*(Num li, const Num& re) { return li *= re; }
friend Num operator/(Num li, const Num& re) { return li /= re; }
friend Num operator%(Num li, const Num& re) { return li %= re; }
// - bitweise
friend Num operator|(Num li, const Num& re) { return li |= re; }
friend Num operator&(Num li, const Num& re) { return li &= re; }
friend Num operator^(Num li, const Num& re) { return li ^= re; }
// - Vergleiche
// - … fundamental für Standardcontainer und -algorithmen
friend bool operator==(const Num& li, const Num& re) { return *li == *re; }
auto operator<=>(const Num& re) const {return val_ <=> *re; } // C++20
// - Ein- und Ausgabe
friend std::ostream& operator<<(std::ostream& os, const Num& arg);
friend std::istream& operator>>(std::istream& is, Num& arg);
};
// einstellige Operatoren
Num& Num::operator++() { ++val_; return *this; }
Num& Num::operator--() { --val_; return *this; }
Num Num::operator+() { return Num{val_}; }
Num Num::operator-() { return Num{-val_}; }
Num Num::operator~() { return Num{~val_}; }
int& Num::operator*() { return val_; }
const int& Num::operator*() const { return val_; }
// Ein- und Ausgabe
std::ostream& operator<<(std::ostream&os, const Num& arg) { return os<<*arg; }
std::istream& operator>>(std::istream&is, Num& arg) { return is>>*arg; }
Godbolt Listing lst-0442-godb.cpp, https://godbolt.org/z/Gf38nTa1q:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Gf38nTa1q
#include <iostream> // istream, ostream, cout
class Num {
int val_ = 0;
public:
int& operator*(); // Dereferenzieren: Zugriff auf den Wert direkt erhalten
const int& operator*() const; // Dereferenzieren: Lesezugriff auf den Wert
Num() {}
explicit Num(int value) : val_{value} {}
// einstellige Operatoren
Num& operator++(); // Pre-Inkrement
Num& operator--(); // Pre-Dekrement
Num operator+(); // Positiv
Num operator-(); // Negieren
Num operator~(); // bitweises Invertieren
// zweistellige Operatoren
// - zusammengesetzte Zuweisungen, arithmetisch
Num& operator+=(const Num& re) { val_ += *re; return *this; }
Num& operator-=(const Num& re) { val_ -= *re; return *this; }
Num& operator*=(const Num& re) { val_ *= *re; return *this; }
Num& operator/=(const Num& re) { val_ /= *re; return *this; }
Num& operator%=(const Num& re) { val_ %= *re; return *this; }
// - zusammengesetzte Zuweisungen, bitweise
Num& operator|=(const Num& re) { val_ |= *re; return *this; }
Num& operator&=(const Num& re) { val_ &= *re; return *this; }
Num& operator^=(const Num& re) { val_ ^= *re; return *this; }
Num& operator<<=(int n) { val_ <<= n; return *this; }
Num& operator>>=(int n) { val_ >>= n; return *this; }
// - Variation zusammengesetzter Zuweisungen, für einfachere Bedienung
Num& operator+=(int re) { val_ += re; return *this; }
Num& operator-=(int re) { val_ -= re; return *this; }
// zweistellige Operatoren, mit Call-by-Value für den ersten Parameter
// und die die zusammengesetzte Zuweisung zu Hilfe nehmen
// - Arithmetik
friend Num operator+(Num li, const Num& re) { return li += re; }
friend Num operator-(Num li, const Num& re) { return li -= re; }
friend Num operator*(Num li, const Num& re) { return li *= re; }
friend Num operator/(Num li, const Num& re) { return li /= re; }
friend Num operator%(Num li, const Num& re) { return li %= re; }
// - bitweise
friend Num operator|(Num li, const Num& re) { return li |= re; }
friend Num operator&(Num li, const Num& re) { return li &= re; }
friend Num operator^(Num li, const Num& re) { return li ^= re; }
// - Vergleiche
// - … fundamental für Standardcontainer und -algorithmen
friend bool operator==(const Num& li, const Num& re) { return *li == *re; }
auto operator<=>(const Num& re) const {return val_ <=> *re; } // C++20
// - Ein- und Ausgabe
friend std::ostream& operator<<(std::ostream& os, const Num& arg);
friend std::istream& operator>>(std::istream& is, Num& arg);
};
// einstellige Operatoren
Num& Num::operator++() { ++val_; return *this; }
Num& Num::operator--() { --val_; return *this; }
Num Num::operator+() { return Num{val_}; }
Num Num::operator-() { return Num{-val_}; }
Num Num::operator~() { return Num{~val_}; }
int& Num::operator*() { return val_; }
const int& Num::operator*() const { return val_; }
// Ein- und Ausgabe
std::ostream& operator<<(std::ostream&os, const Num& arg) { return os<<*arg; }
std::istream& operator>>(std::istream&is, Num& arg) { return is>>*arg; }
Listing 16.25: Sie verwenden den mit Operatoren ausgestatteten Datentyp wie gewohnt.
Book listing lst-0443-book.cpp:
// https://godbolt.org/z/asaYr3ox6
#include <iostream> // cout
int main() {
using std::cout;
Num a{1};
*a = 7; // operator* liefert auch int&
a += Num{3}; // Inkrement mit Num
cout << ( ++( ++a ) ) << "\n"; // Ausgabe: 12
a -= 2; // Variation mit int
cout << --(--a) << "\n"; // Ausgabe: 8
Num b{99};
cout << (a<b ? "ja\n" : "xxx\n"); // Ausgabe: ja
cout << (a>b ? "xxx\n" : "nein\n"); // Ausgabe: nein
b /= Num{3}; // b: 33
b %= Num{10}; // b: 3
b <<= 4; // b: 48
b >>= 2; // b: 12
Num c = b / Num{3} + a * Num{2}; // c: 20
}
Godbolt Listing lst-0443-godb.cpp, https://godbolt.org/z/asaYr3ox6:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/asaYr3ox6
#include <iostream> // cout
int main() {
using std::cout;
Num a{1};
*a = 7; // operator* liefert auch int&
a += Num{3}; // Inkrement mit Num
cout << ( ++( ++a ) ) << "\n"; // Ausgabe: 12
a -= 2; // Variation mit int
cout << --(--a) << "\n"; // Ausgabe: 8
Num b{99};
cout << (a<b ? "ja\n" : "xxx\n"); // Ausgabe: ja
cout << (a>b ? "xxx\n" : "nein\n"); // Ausgabe: nein
b /= Num{3}; // b: 33
b %= Num{10}; // b: 3
b <<= 4; // b: 48
b >>= 2; // b: 12
Num c = b / Num{3} + a * Num{2}; // c: 20
}
Listing 16.26: Dieser Datentyp demonstriert die booleschen Operatoren.
Book listing lst-0444-book.cpp:
// https://godbolt.org/z/ojeh8Gzcx
#include <iostream> // istream, ostream, cout
class Bool {
bool val_ = false;
bool& operator*() // dereferenzieren; veränderbar
{ return val_; };
const bool& operator*() const // dereferenzieren; nur lesen
{ return val_; }
public:
constexpr Bool() {}
explicit constexpr Bool(bool value)
: val_{value} {}
// einstellige Operatoren
Bool operator!() const // Nicht-Operator
{ return Bool{!val_}; };
// zweistellige Operatoren
friend Bool operator&&(const Bool &re, const Bool &li)
{ return Bool{*re && *li}; }
friend Bool operator||(const Bool &re, const Bool &li)
{ return Bool{*re || *li}; }
// Ein- und Ausgabe
friend std::ostream& operator<<(std::ostream& os, const Bool& arg);
friend std::istream& operator>>(std::istream& is, Bool& arg);
};
std::ostream& operator<<(std::ostream& os, const Bool& arg)
{ return os << *arg; }
std::istream& operator>>(std::istream& is, Bool& arg)
{ return is >> *arg; }
// Konstanten
static constexpr Bool False{false};
static constexpr Bool True{true};
int main() {
Bool jein = True && ( Bool{false} || !Bool{} ); // verwendet &&, || und !
std::cout << jein << "\n"; // Ausgabe: 1
}
Godbolt Listing lst-0444-godb.cpp, https://godbolt.org/z/ojeh8Gzcx:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/ojeh8Gzcx
#include <iostream> // istream, ostream, cout
class Bool {
bool val_ = false;
bool& operator*() // dereferenzieren; veränderbar
{ return val_; };
const bool& operator*() const // dereferenzieren; nur lesen
{ return val_; }
public:
constexpr Bool() {}
explicit constexpr Bool(bool value)
: val_{value} {}
// einstellige Operatoren
Bool operator!() const // Nicht-Operator
{ return Bool{!val_}; };
// zweistellige Operatoren
friend Bool operator&&(const Bool &re, const Bool &li)
{ return Bool{*re && *li}; }
friend Bool operator||(const Bool &re, const Bool &li)
{ return Bool{*re || *li}; }
// Ein- und Ausgabe
friend std::ostream& operator<<(std::ostream& os, const Bool& arg);
friend std::istream& operator>>(std::istream& is, Bool& arg);
};
std::ostream& operator<<(std::ostream& os, const Bool& arg)
{ return os << *arg; }
std::istream& operator>>(std::istream& is, Bool& arg)
{ return is >> *arg; }
// Konstanten
static constexpr Bool False{false};
static constexpr Bool True{true};
int main() {
Bool jein = True && ( Bool{false} || !Bool{} ); // verwendet &&, || und !
std::cout << jein << "\n"; // Ausgabe: 1
}
Listing 16.27: Die Vergleichskategorien enthalten Konstanten für die Rückgabe.
Book listing lst-0446-book.cpp:
// https://godbolt.org/z/KxWb4q8q9
#include <compare> // partial_ordering etc
#include <set>
#include <iostream>
using namespace std;
struct Bruch {
int z, n; // zaehler / nenner
partial_ordering operator<=>(const Bruch& re) const {
if(n==0 || re.n==0) return partial_ordering::unordered;
return (double)z / n <=> (double)re.z / re.n;
}
};
int main() {
set<Bruch> brueche{ {1,2}, {2,4}, {1,3}, {2,3}, {1,4}, {2,5}, {3,8}, {99,0} };
for(auto b : brueche)
cout << b.z << "/" << b.n << " ";
cout << "\n"; // Ausgabe: 1/4 1/3 3/8 2/5 1/2 2/3
}
Godbolt Listing lst-0446-godb.cpp, https://godbolt.org/z/KxWb4q8q9:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/KxWb4q8q9
#include <compare> // partial_ordering etc
#include <set>
#include <iostream>
using namespace std;
struct Bruch {
int z, n; // zaehler / nenner
partial_ordering operator<=>(const Bruch& re) const {
if(n==0 || re.n==0) return partial_ordering::unordered;
return (double)z / n <=> (double)re.z / re.n;
}
};
int main() {
set<Bruch> brueche{ {1,2}, {2,4}, {1,3}, {2,3}, {1,4}, {2,5}, {3,8}, {99,0} };
for(auto b : brueche)
cout << b.z << "/" << b.n << " ";
cout << "\n"; // Ausgabe: 1/4 1/3 3/8 2/5 1/2 2/3
}
Listing 16.28: Die Rückgabe von <=> können Sie mit null vergleichen.
Book listing lst-0448-book.cpp:
auto operator<=>(const Adresse& re) const {
array a{strasse, plz, ort};
array b{re.strasse, re.plz, re.ort};
return lexicographical_compare_three_way(begin(a), end(a), begin(b), end(b));
}
Listing 16.29: Eine virtuelle Methode, die = 0 ist, nennt man pur virtuell oder abstrakt.
Book listing lst-0449-book.cpp:
// https://godbolt.org/z/f458s99Ga
#include <string>
#include <iostream>
using std::string; using std::ostream;
class Shape {
string color_;
public:
virtual double calcArea() const = 0; // pur virtuelle Methode
string getColor() const { return color_; }
void setColor(const string& color) { color_ = color; }
virtual ~Shape() {}
};
class Square : public Shape {
double len_;
public:
explicit Square(double len) : len_{len} {}
double calcArea() const override { return len_*len_; }
};
class Circle : public Shape {
double rad_;
public:
explicit Circle(double rad) : rad_{rad} {}
double calcArea() const override { return 3.1415*rad_*rad_; }
};
struct Calculator {
Shape& shape_;
Calculator(Shape& shape) : shape_{shape} { }
void run(ostream& os) const {
os << "The area of the shape is " << shape_.calcArea() << "\n";
}
};
int main() {
Square quadrat {5.0};
Calculator ti { quadrat };
ti.run(std::cout); // Ausgabe: The area of the shape is 25
}
Godbolt Listing lst-0449-godb.cpp, https://godbolt.org/z/f458s99Ga:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/f458s99Ga
#include <string>
#include <iostream>
using std::string; using std::ostream;
class Shape {
string color_;
public:
virtual double calcArea() const = 0; // pur virtuelle Methode
string getColor() const { return color_; }
void setColor(const string& color) { color_ = color; }
virtual ~Shape() {}
};
class Square : public Shape {
double len_;
public:
explicit Square(double len) : len_{len} {}
double calcArea() const override { return len_*len_; }
};
class Circle : public Shape {
double rad_;
public:
explicit Circle(double rad) : rad_{rad} {}
double calcArea() const override { return 3.1415*rad_*rad_; }
};
struct Calculator {
Shape& shape_;
Calculator(Shape& shape) : shape_{shape} { }
void run(ostream& os) const {
os << "The area of the shape is " << shape_.calcArea() << "\n";
}
};
int main() {
Square quadrat {5.0};
Calculator ti { quadrat };
ti.run(std::cout); // Ausgabe: The area of the shape is 25
}
Listing 16.30: Mit einem »enum« definieren Sie einen Typ mit eigenem Wertebereich.
Book listing lst-0454-book.cpp:
// https://godbolt.org/z/xhd7s1YhE
#include <string>
using std::string;
enum class Ampelfarbe {
ROT, GELB, ROTGELB, GRUEN
};
struct Ampel {
Ampelfarbe farbe_;
Ampel(Ampelfarbe farbe, string name) : farbe_{farbe} {}
};
Ampel erzeugeAmpel(Ampelfarbe farbe, string ampelName) {
return Ampel{farbe, ampelName};
}
int main() {
Ampel ampel = erzeugeAmpel(Ampelfarbe::ROT, "AX-001");
}
Godbolt Listing lst-0454-godb.cpp, https://godbolt.org/z/xhd7s1YhE:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/xhd7s1YhE
#include <string>
using std::string;
enum class Ampelfarbe {
ROT, GELB, ROTGELB, GRUEN
};
struct Ampel {
Ampelfarbe farbe_;
Ampel(Ampelfarbe farbe, string name) : farbe_{farbe} {}
};
Ampel erzeugeAmpel(Ampelfarbe farbe, string ampelName) {
return Ampel{farbe, ampelName};
}
int main() {
Ampel ampel = erzeugeAmpel(Ampelfarbe::ROT, "AX-001");
}
Listing 16.31: In einem »enum« können Sie auch die gewünschten Zahlenwerte angeben.
Book listing lst-0457-book.cpp:
// https://godbolt.org/z/esevnfEM3
enum class Wochentag {
MO=1, DI, MI, DO, FR, SA, SO // DI wird 2, MI wird 3 etc.
};
enum class Level {
TRACE=1, DEBUG, INFO=10, ERROR, FATAL // auch mit Lücken möglich
};
void log(Level level) {
int intLevel = (int)level; // explizit in einen int umwandeln
if(intLevel > 10) { /* ... */ }
}
Godbolt Listing lst-0457-godb.cpp, https://godbolt.org/z/esevnfEM3:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/esevnfEM3
enum class Wochentag {
MO=1, DI, MI, DO, FR, SA, SO // DI wird 2, MI wird 3 etc.
};
enum class Level {
TRACE=1, DEBUG, INFO=10, ERROR, FATAL // auch mit Lücken möglich
};
void log(Level level) {
int intLevel = (int)level; // explizit in einen int umwandeln
if(intLevel > 10) { /* ... */ }
}
Listing 17.1: Verbieten Sie mit »= delete« vier der großen Fünf.
Book listing lst-0458-book.cpp:
// https://godbolt.org/z/1Ke5W5Pj5
struct Typ {
char* data_; // roher Zeiger kann für unklare Besitzverhältnisse sorgen
Typ(int n) : data_(new char[n]) {}
~Typ() { delete[] data_; } // den Destruktor benötigen Sie
Typ(const Typ&) = delete; // keine Kopie zulassen
Typ& operator=(const Typ&) = delete; // keine Zuweisung bitte
Typ(Typ&&) = delete; // kein Verschieben
Typ& operator=(Typ&&) = delete; // kein Verschiebeoperator
};
Godbolt Listing lst-0458-godb.cpp, https://godbolt.org/z/1Ke5W5Pj5:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/1Ke5W5Pj5
struct Typ {
char* data_; // roher Zeiger kann für unklare Besitzverhältnisse sorgen
Typ(int n) : data_(new char[n]) {}
~Typ() { delete[] data_; } // den Destruktor benötigen Sie
Typ(const Typ&) = delete; // keine Kopie zulassen
Typ& operator=(const Typ&) = delete; // keine Zuweisung bitte
Typ(Typ&&) = delete; // kein Verschieben
Typ& operator=(Typ&&) = delete; // kein Verschiebeoperator
};
Listing 17.2: Statt eines rohen Zeigers verwenden Sie ein Standardkonstrukt und definieren keine Operation der Großen Fünf.
Book listing lst-0459-book.cpp:
// https://godbolt.org/z/xMbG771En
#include <vector>
#include <memory> // unique_ptr, shared_ptr
struct Typ1 { // automatische komplette Kopie der Ressource
std::vector<char> data_;
Typ1(int n) : data_(n) {}
};
struct Typ2 { // Kopie untersagt, Verschieben möglich
std::unique_ptr<int[]> data_;
Typ2(int n) : data_(new int[n]) {}
};
struct Typ3 { // Kopie erlaubt, Ressource wird dann sauber geteilt
std::shared_ptr<Typ1> data_;
Typ3(int n) : data_(std::make_shared<Typ1>(n)) {}
};
Godbolt Listing lst-0459-godb.cpp, https://godbolt.org/z/xMbG771En:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/xMbG771En
#include <vector>
#include <memory> // unique_ptr, shared_ptr
struct Typ1 { // automatische komplette Kopie der Ressource
std::vector<char> data_;
Typ1(int n) : data_(n) {}
};
struct Typ2 { // Kopie untersagt, Verschieben möglich
std::unique_ptr<int[]> data_;
Typ2(int n) : data_(new int[n]) {}
};
struct Typ3 { // Kopie erlaubt, Ressource wird dann sauber geteilt
std::shared_ptr<Typ1> data_;
Typ3(int n) : data_(std::make_shared<Typ1>(n)) {}
};
Listing 17.3: In einer Hierarchie mit virtuellen Methoden müssen Sie den Destruktor der Basisklasse definieren und virtuell markieren.
Book listing lst-0460-book.cpp:
// https://godbolt.org/z/1xcqon7dM
struct Base {
virtual ~Base() {}; // definieren Sie den Destruktor, machen Sie ihn virtual
virtual void other();
};
struct Derived : public Base {
void other() override;
};
int main() {
Base *obj = new Derived{};
/* ... mehr Programmzeilen hier ... */
delete obj; // klappt, weil Base::~Base virtual ist
}
Godbolt Listing lst-0460-godb.cpp, https://godbolt.org/z/1xcqon7dM:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/1xcqon7dM
struct Base {
virtual ~Base() {}; // definieren Sie den Destruktor, machen Sie ihn virtual
virtual void other();
};
struct Derived : public Base {
void other() override;
};
int main() {
Base *obj = new Derived{};
/* ... mehr Programmzeilen hier ... */
delete obj; // klappt, weil Base::~Base virtual ist
}
Listing 17.4: shared_ptr ruft immer den richtigen Destruktor auf, virtuell oder nicht.
Book listing lst-0461-book.cpp:
int main() {
shared_ptr<Base> obj{ new Derived{} };
/* ... mehr Programmzeilen hier ... */
} // obj wird korrekt weggeräumt
Listing 17.5: Eine RAII-Zeichenpufferklasse
Book listing lst-0463-book.cpp:
// https://godbolt.org/z/9eeG575Wz
struct Puffer {
const char *data;
explicit Puffer(unsigned sz): data(new char[sz]) {}
~Puffer() { delete[] data; }
Puffer(const Puffer&) = delete;
Puffer& operator=(const Puffer&) = delete;
};
Godbolt Listing lst-0463-godb.cpp, https://godbolt.org/z/9eeG575Wz:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/9eeG575Wz
struct Puffer {
const char *data;
explicit Puffer(unsigned sz): data(new char[sz]) {}
~Puffer() { delete[] data; }
Puffer(const Puffer&) = delete;
Puffer& operator=(const Puffer&) = delete;
};
Listing 17.6: Wirft »right« eine Exception, entsteht mit »left« ein Leck.
Book listing lst-0464-book.cpp:
// https://godbolt.org/z/TK3vTv1EM
struct StereoImage {
Image *left, *right;
StereoImage()
: left(new Image)
, right(new Image) // Gefahr!
{ }
~StereoImage() {
delete left;
delete right;
}
};
Godbolt Listing lst-0464-godb.cpp, https://godbolt.org/z/TK3vTv1EM:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/TK3vTv1EM
struct StereoImage {
Image *left, *right;
StereoImage()
: left(new Image)
, right(new Image) // Gefahr!
{ }
~StereoImage() {
delete left;
delete right;
}
};
Listing 17.7: Korrektes RAII für »StereoImage«
Book listing lst-0465-book.cpp:
// https://godbolt.org/z/cs4eEEGrf
#include <memory> // unique_ptr
struct Image {
/* ... */
};
struct StereoImage {
std::unique_ptr<Image> left, right;
StereoImage()
: left(new Image)
, right(new Image)
{ }
};
Godbolt Listing lst-0465-godb.cpp, https://godbolt.org/z/cs4eEEGrf:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/cs4eEEGrf
#include <memory> // unique_ptr
struct Image {
/* ... */
};
struct StereoImage {
std::unique_ptr<Image> left, right;
StereoImage()
: left(new Image)
, right(new Image)
{ }
};
Listing 17.8: C-API in C++-Code
Book listing lst-0466-book.cpp:
// https://godbolt.org/z/GK4W1nKd4
#include <string>
#include <stdexcept>
#include <sqlite3.h>
using std::string; using std::runtime_error;
void dbExec(const string &dbname, const string &sql) {
sqlite3 *db;
int errCode = sqlite3_open(dbname.c_str(), &db); // Acquire
if(errCode) {
throw runtime_error("Fehler beim Öffnen der DB.");
}
errCode = sqlite3_exec(db, sql.c_str(), nullptr, nullptr, nullptr);
if(errCode) {
throw runtime_error("Fehler SQL-Exec."); // (ERR) Nicht gut!
}
errCode = sqlite3_close(db); // Release
}
Godbolt Listing lst-0466-godb.cpp, https://godbolt.org/z/GK4W1nKd4:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/GK4W1nKd4
#include <string>
#include <stdexcept>
#include <sqlite3.h>
using std::string; using std::runtime_error;
void dbExec(const string &dbname, const string &sql) {
sqlite3 *db;
int errCode = sqlite3_open(dbname.c_str(), &db); // Acquire
if(errCode) {
throw runtime_error("Fehler beim Öffnen der DB.");
}
errCode = sqlite3_exec(db, sql.c_str(), nullptr, nullptr, nullptr);
if(errCode) {
throw runtime_error("Fehler SQL-Exec."); // (ERR) Nicht gut!
}
errCode = sqlite3_close(db); // Release
}
Listing 17.9: C-API mit einfachem RAII
Book listing lst-0467-book.cpp:
// https://godbolt.org/z/hqrPjGjnK
#include <sqlite3.h>
class DbWrapper {
sqlite3 *db_;
public:
// acquire resource
DbWrapper(const string& dbname)
: db_{nullptr}
{
const int errCode = sqlite3_open(dbname.c_str(), &db_);
if(errCode)
throw runtime_error("Fehler beim Öffnen"); // verhindert sqlite3_close
}
// release resource
~DbWrapper() {
sqlite3_close(db_); // Release
}
// access Resource
sqlite3* operator*() { return db_; }
// Keine Kopie und Zuweisung
DbWrapper(const DbWrapper&) = delete;
DbWrapper& operator=(const DbWrapper&) = delete;
};
void dbExec(const string &dbname, const string &sql) {
DbWrapper db { dbname };
const int errCode = sqlite3_exec(*db, sql.c_str(), nullptr,
nullptr, nullptr);
if(errCode)
throw runtime_error("Fehler SQL-Exec."); // Jetzt geht es!
}
Godbolt Listing lst-0467-godb.cpp, https://godbolt.org/z/hqrPjGjnK:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/hqrPjGjnK
#include <sqlite3.h>
class DbWrapper {
sqlite3 *db_;
public:
// acquire resource
DbWrapper(const string& dbname)
: db_{nullptr}
{
const int errCode = sqlite3_open(dbname.c_str(), &db_);
if(errCode)
throw runtime_error("Fehler beim Öffnen"); // verhindert sqlite3_close
}
// release resource
~DbWrapper() {
sqlite3_close(db_); // Release
}
// access Resource
sqlite3* operator*() { return db_; }
// Keine Kopie und Zuweisung
DbWrapper(const DbWrapper&) = delete;
DbWrapper& operator=(const DbWrapper&) = delete;
};
void dbExec(const string &dbname, const string &sql) {
DbWrapper db { dbname };
const int errCode = sqlite3_exec(*db, sql.c_str(), nullptr,
nullptr, nullptr);
if(errCode)
throw runtime_error("Fehler SQL-Exec."); // Jetzt geht es!
}
Listing 17.10: C-API mit einfachem RAII, ohne throw
Book listing lst-0468-book.cpp:
// https://godbolt.org/z/5bW9Evorc
#include <string>
#include <sqlite3.h>
class DbWrapper {
sqlite3 *db_;
public:
DbWrapper(const std::string& dbname)
: db_{nullptr}
{
const int errCode = sqlite3_open(dbname.c_str(), &db_);
if(errCode) db_ = nullptr; // als 'nicht erfolgreich' markieren
}
explicit operator bool() const {
return db_ != nullptr; // Markierung auswerten
}
~DbWrapper() {
if(db_) sqlite3_close(db_);
}
// ... Rest wie zuvor ...
};
bool dbExec(const std::string &dbname, const std::string &sql) {
DbWrapper db { dbname };
if(db) { // prüfe auf erfolgreiche Initialisierung
const int errCode = sqlite3_exec(*db,sql.c_str(),nullptr,nullptr,nullptr);
if(errCode)
return false; // immer noch korrektes RAII
}
return (bool)db;
}
Godbolt Listing lst-0468-godb.cpp, https://godbolt.org/z/5bW9Evorc:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/5bW9Evorc
#include <string>
#include <sqlite3.h>
class DbWrapper {
sqlite3 *db_;
public:
DbWrapper(const std::string& dbname)
: db_{nullptr}
{
const int errCode = sqlite3_open(dbname.c_str(), &db_);
if(errCode) db_ = nullptr; // als 'nicht erfolgreich' markieren
}
explicit operator bool() const {
return db_ != nullptr; // Markierung auswerten
}
~DbWrapper() {
if(db_) sqlite3_close(db_);
}
// ... Rest wie zuvor ...
};
bool dbExec(const std::string &dbname, const std::string &sql) {
DbWrapper db { dbname };
if(db) { // prüfe auf erfolgreiche Initialisierung
const int errCode = sqlite3_exec(*db,sql.c_str(),nullptr,nullptr,nullptr);
if(errCode)
return false; // immer noch korrektes RAII
}
return (bool)db;
}
Listing 17.11: Nothrow-new wirft kein »bad_alloc«, sondern liefert »nullptr« zurück.
Book listing lst-0469-book.cpp:
// https://godbolt.org/z/s8KoE4ETs
#include <new> // nothrow
std::string *ps = new(std::nothrow) std::string{};
if(ps == nullptr) {
std::cerr << "Die Speicheranforderung ging schief\n";
return SOME_ERROR;
}
Godbolt Listing lst-0469-godb.cpp, https://godbolt.org/z/s8KoE4ETs:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/s8KoE4ETs
#include <new> // nothrow
std::string *ps = new(std::nothrow) std::string{};
if(ps == nullptr) {
std::cerr << "Die Speicheranforderung ging schief\n";
return SOME_ERROR;
}
Listing 18.1: Mit friend können Sie einer anderen Klasse Zugriff auf Privates erlauben.
Book listing lst-0470-book.cpp:
// https://godbolt.org/z/WqfMGaP71
#include <iostream>
class Schrauber;
class Ding {
int value_; // privat
public:
explicit Ding(int value) : value_{value} {}
void inc() { ++value_; }
std::ostream& print(std::ostream& os) const { return os<<value_; }
friend class Schrauber;
};
class Schrauber {
const Ding &ding_;
public:
explicit Schrauber(const Ding &ding) : ding_{ding} {}
auto dingWert() const {
return ding_.value_; // Zugriff auf Privates aus Ding
}
};
int main() {
Ding ding{45};
ding.print(std::cout) << '\n'; // Ausgabe: 45
Schrauber schrauber{ding};
ding.inc(); // internen Wert verändern
std::cout << schrauber.dingWert() << '\n'; // Ausgabe: 46
}
Godbolt Listing lst-0470-godb.cpp, https://godbolt.org/z/WqfMGaP71:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/WqfMGaP71
#include <iostream>
class Schrauber;
class Ding {
int value_; // privat
public:
explicit Ding(int value) : value_{value} {}
void inc() { ++value_; }
std::ostream& print(std::ostream& os) const { return os<<value_; }
friend class Schrauber;
};
class Schrauber {
const Ding &ding_;
public:
explicit Schrauber(const Ding &ding) : ding_{ding} {}
auto dingWert() const {
return ding_.value_; // Zugriff auf Privates aus Ding
}
};
int main() {
Ding ding{45};
ding.print(std::cout) << '\n'; // Ausgabe: 45
Schrauber schrauber{ding};
ding.inc(); // internen Wert verändern
std::cout << schrauber.dingWert() << '\n'; // Ausgabe: 46
}
Listing 18.2: Die Klasse Tree hat Zugriff auf Privates von Node.
Book listing lst-0471-book.cpp:
// https://godbolt.org/z/dTnxobz6v
#include <memory> // unique_ptr
#include <string>
using std::unique_ptr; using std::cout;
template <typename K, typename D> class Tree; // Vorwärtsdeklaration
template <typename K, typename D>
class Node {
friend class Tree<K,D>; // Zugriff auf Privates erlauben
K key;
D data;
unique_ptr<Node> left, right;
public:
Node(const K& k, const D& d) : key(k), data(d) { }
};
template <typename K, typename D>
class Tree {
public:
void insert(const K &key, const D& data);
D* find(const K &key) { return findRec(key, root); }
private:
D* findRec(const K &key, unique_ptr<Node<K,D>> &wo);
unique_ptr<Node<K,D>> root;
};
template <typename K, typename D>
void Tree<K,D>::insert(const K& key, const D& data) {
auto *current = &root;
while(*current) { // solange unique_ptr was enthält
auto &node = *(current->get());
if (key < node.key) {
current = &node.left;
} else if (node.key < key) {
current = &node.right;
}
}
*current = std::make_unique<Node<K,D>>(key,data);
};
template <typename K, typename D>
D* Tree<K,D>::findRec(const K& key, unique_ptr<Node<K,D>> &wo) {
if(!wo)
return nullptr;
auto &node = *(wo.get());
if(key < node.key)
return findRec(key, node.left);
if(node.key < key)
return findRec(key, node.right);
return &node.data; // key == node.key
};
int main() {
Tree<int,std::string> bt {};
bt.insert(3, "drei");
bt.insert(2, "zwei");
bt.insert(4, "vier");
auto wo = bt.find(7);
if(wo==nullptr) cout<<"keine 7\n"; // Ausgabe: keine 7
wo = bt.find(3);
if(wo!=nullptr) cout<<*wo<<"\n"; // Ausgabe: drei
}
Godbolt Listing lst-0471-godb.cpp, https://godbolt.org/z/dTnxobz6v:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/dTnxobz6v
#include <memory> // unique_ptr
#include <string>
using std::unique_ptr; using std::cout;
template <typename K, typename D> class Tree; // Vorwärtsdeklaration
template <typename K, typename D>
class Node {
friend class Tree<K,D>; // Zugriff auf Privates erlauben
K key;
D data;
unique_ptr<Node> left, right;
public:
Node(const K& k, const D& d) : key(k), data(d) { }
};
template <typename K, typename D>
class Tree {
public:
void insert(const K &key, const D& data);
D* find(const K &key) { return findRec(key, root); }
private:
D* findRec(const K &key, unique_ptr<Node<K,D>> &wo);
unique_ptr<Node<K,D>> root;
};
template <typename K, typename D>
void Tree<K,D>::insert(const K& key, const D& data) {
auto *current = &root;
while(*current) { // solange unique_ptr was enthält
auto &node = *(current->get());
if (key < node.key) {
current = &node.left;
} else if (node.key < key) {
current = &node.right;
}
}
*current = std::make_unique<Node<K,D>>(key,data);
};
template <typename K, typename D>
D* Tree<K,D>::findRec(const K& key, unique_ptr<Node<K,D>> &wo) {
if(!wo)
return nullptr;
auto &node = *(wo.get());
if(key < node.key)
return findRec(key, node.left);
if(node.key < key)
return findRec(key, node.right);
return &node.data; // key == node.key
};
int main() {
Tree<int,std::string> bt {};
bt.insert(3, "drei");
bt.insert(2, "zwei");
bt.insert(4, "vier");
auto wo = bt.find(7);
if(wo==nullptr) cout<<"keine 7\n"; // Ausgabe: keine 7
wo = bt.find(3);
if(wo!=nullptr) cout<<*wo<<"\n"; // Ausgabe: drei
}
Listing 18.3: Beim Erben können Sie angeben, was sichtbar werden soll.
Book listing lst-0473-book.cpp:
// https://godbolt.org/z/eKbK39nG1
class Base {
public:
int xPublic = 1;
protected:
int xProtected = 2;
private:
int xPrivate = 3;
};
class DerivedPublic : public Base {
// xPublic wird 'public'
// xProtected wird 'protected'
// xPrivate ist hier nicht sichtbar
};
class DerivedProtected : protected Base {
// xPublic wird 'protected'
// xProtected wird 'protected'
// xPrivate ist hier nicht sichtbar
};
class DerivedPrivate : private Base { // oder wenn nichts angegeben
// xPublic wird 'private'
// xProtected wird 'private'
// xPrivate ist hier nicht sichtbar
};
Godbolt Listing lst-0473-godb.cpp, https://godbolt.org/z/eKbK39nG1:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/eKbK39nG1
class Base {
public:
int xPublic = 1;
protected:
int xProtected = 2;
private:
int xPrivate = 3;
};
class DerivedPublic : public Base {
// xPublic wird 'public'
// xProtected wird 'protected'
// xPrivate ist hier nicht sichtbar
};
class DerivedProtected : protected Base {
// xPublic wird 'protected'
// xProtected wird 'protected'
// xPrivate ist hier nicht sichtbar
};
class DerivedPrivate : private Base { // oder wenn nichts angegeben
// xPublic wird 'private'
// xProtected wird 'private'
// xPrivate ist hier nicht sichtbar
};
Listing 18.4: Ererbte Sichtbarkeiten, von außen betrachtet
Book listing lst-0474-book.cpp:
// https://godbolt.org/z/Pxqrjjqs8
#include <iostream>
using std::cout; using std::ostream;
// … wie zuvor …
int main() {
// öffentlich erben
DerivedPublic dpu{};
cout << dpu.xPublic << '\n'; // Ausgabe: 1
cout << dpu.xProtected << '\n'; // kein Zugriff von außen
// geschützt erben
DerivedProtected dpt{};
cout << dpt.xPublic << '\n'; // kein Zugriff von außen
cout << dpt.xProtected << '\n'; // kein Zugriff von außen
// private erben
DerivedPrivate dpv{};
cout << dpv.xPublic << '\n'; // kein Zugriff von außen
cout << dpv.xProtected << '\n'; // kein Zugriff von außen
}
Godbolt Listing lst-0474-godb.cpp, https://godbolt.org/z/Pxqrjjqs8:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Pxqrjjqs8
#include <iostream>
using std::cout; using std::ostream;
// … wie zuvor …
int main() {
// öffentlich erben
DerivedPublic dpu{};
cout << dpu.xPublic << '\n'; // Ausgabe: 1
cout << dpu.xProtected << '\n'; // kein Zugriff von außen
// geschützt erben
DerivedProtected dpt{};
cout << dpt.xPublic << '\n'; // kein Zugriff von außen
cout << dpt.xProtected << '\n'; // kein Zugriff von außen
// private erben
DerivedPrivate dpv{};
cout << dpv.xPublic << '\n'; // kein Zugriff von außen
cout << dpv.xProtected << '\n'; // kein Zugriff von außen
}
Listing 18.5: Ererbte Sichtbarkeiten für weitere Ableitungen
Book listing lst-0475-book.cpp:
// https://godbolt.org/z/xKEo38c4n
#include <iostream>
using std::cout; using std::ostream;
// … wie zuvor …
struct Normalfall : public DerivedPublic {
void drucke() {
cout << xPublic;
cout << xProtected;
}
};
struct Spezialfall : public DerivedPrivate {
void drucke() {
cout << xPublic; // (ERR) kein Zugriff
cout << xProtected; // (ERR) kein Zugriff
}
};
int main() {
Normalfall n {};
n.drucke(); // Ausgabe: 12
Spezialfall s {};
s.drucke();
}
Godbolt Listing lst-0475-godb.cpp, https://godbolt.org/z/xKEo38c4n:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/xKEo38c4n
#include <iostream>
using std::cout; using std::ostream;
// … wie zuvor …
struct Normalfall : public DerivedPublic {
void drucke() {
cout << xPublic;
cout << xProtected;
}
};
struct Spezialfall : public DerivedPrivate {
void drucke() {
cout << xPublic; // (ERR) kein Zugriff
cout << xProtected; // (ERR) kein Zugriff
}
};
int main() {
Normalfall n {};
n.drucke(); // Ausgabe: 12
Spezialfall s {};
s.drucke();
}
Listing 18.6: In der Praxis nutzen Kindklassen privat Geerbtes indirekt.
Book listing lst-0476-book.cpp:
// https://godbolt.org/z/zMvWxT854
#include <iostream>
using std::cout; using std::ostream;
class Basis {
public: int daten = 5;
};
class Mitte : private Basis {
protected: void drucke() {
cout << daten; // 'daten' ist hier privat geerbt
}
};
class Letztendlich : public Mitte {
public: void los() {
// 'daten' ist nicht sichtbar
drucke(); // 'drucke' ist geschützt sichtbar
}
};
int main() {
Letztendlich l {};
l.los(); // Ausgabe: 5
}
Godbolt Listing lst-0476-godb.cpp, https://godbolt.org/z/zMvWxT854:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/zMvWxT854
#include <iostream>
using std::cout; using std::ostream;
class Basis {
public: int daten = 5;
};
class Mitte : private Basis {
protected: void drucke() {
cout << daten; // 'daten' ist hier privat geerbt
}
};
class Letztendlich : public Mitte {
public: void los() {
// 'daten' ist nicht sichtbar
drucke(); // 'drucke' ist geschützt sichtbar
}
};
int main() {
Letztendlich l {};
l.los(); // Ausgabe: 5
}
Listing 18.7: »Hat-ein«-Beziehung mittels privater Vererbung
Book listing lst-0477-book.cpp:
// https://godbolt.org/z/zzT17q588
class Motor {
public:
Motor(int anzZylinder);
void start(); // Motor starten
};
class Auto : private Motor { // Auto hat-einen Motor
public:
Auto() : Motor{8} { } // initialisiert ein Auto mit 8 Zylindern
using Motor::start; // startet Auto durch Starten des Motors
};
Godbolt Listing lst-0477-godb.cpp, https://godbolt.org/z/zzT17q588:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/zzT17q588
class Motor {
public:
Motor(int anzZylinder);
void start(); // Motor starten
};
class Auto : private Motor { // Auto hat-einen Motor
public:
Auto() : Motor{8} { } // initialisiert ein Auto mit 8 Zylindern
using Motor::start; // startet Auto durch Starten des Motors
};
Listing 18.8: »Hat-ein«-Beziehung mittels Mitglied
Book listing lst-0478-book.cpp:
// https://godbolt.org/z/8jGWTqh9z
class Auto {
public:
Auto() : motor_{8} { } // initialisiert ein Auto mit 8 Zylindern
void start() { motor_.start(); } // startet Auto durch Starten des Motors
private:
Motor motor_; // Auto hat-einen Motor
};
Godbolt Listing lst-0478-godb.cpp, https://godbolt.org/z/8jGWTqh9z:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/8jGWTqh9z
class Auto {
public:
Auto() : motor_{8} { } // initialisiert ein Auto mit 8 Zylindern
void start() { motor_.start(); } // startet Auto durch Starten des Motors
private:
Motor motor_; // Auto hat-einen Motor
};
Listing 18.9: Eine Signaturklasse hat nur pur virtuelle Methoden.
Book listing lst-0479-book.cpp:
// https://godbolt.org/z/rW4oTPhrG
struct Driver {
virtual void init() = 0;
virtual void done() = 0;
virtual bool send(const char* data, unsigned len) = 0;
};
Godbolt Listing lst-0479-godb.cpp, https://godbolt.org/z/rW4oTPhrG:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/rW4oTPhrG
struct Driver {
virtual void init() = 0;
virtual void done() = 0;
virtual bool send(const char* data, unsigned len) = 0;
};
Listing 18.10: Eine Signaturklasse macht eine gute Basisklasse.
Book listing lst-0480-book.cpp:
// https://godbolt.org/z/7xf6sxPqG
#include <iostream>
using std::cout;
struct KeyboardDriver : public Driver {
void init() override { cout << "Init Keyboard\n"; }
void done() override { cout << "Done Keyboard\n"; }
bool send(const char* data, unsigned int len) override {
cout << "sending " << len << " bytes\n";
return true;
}
};
struct Computer {
Driver &driver_;
explicit Computer(Driver &driver) : driver_{driver} {
driver_.init();
}
void run() {
driver_.send("Hello", 5);
}
~Computer() {
driver_.done();
}
Computer(const Computer&) = delete;
};
int main() {
KeyboardDriver keyboard {};
Computer computer(keyboard); // Ausgabe: Init Keyboard
computer.run(); // Ausgabe: sending 5 bytes
} // Ausgabe: Done Keyboard
Godbolt Listing lst-0480-godb.cpp, https://godbolt.org/z/7xf6sxPqG:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/7xf6sxPqG
#include <iostream>
using std::cout;
struct KeyboardDriver : public Driver {
void init() override { cout << "Init Keyboard\n"; }
void done() override { cout << "Done Keyboard\n"; }
bool send(const char* data, unsigned int len) override {
cout << "sending " << len << " bytes\n";
return true;
}
};
struct Computer {
Driver &driver_;
explicit Computer(Driver &driver) : driver_{driver} {
driver_.init();
}
void run() {
driver_.send("Hello", 5);
}
~Computer() {
driver_.done();
}
Computer(const Computer&) = delete;
};
int main() {
KeyboardDriver keyboard {};
Computer computer(keyboard); // Ausgabe: Init Keyboard
computer.run(); // Ausgabe: sending 5 bytes
} // Ausgabe: Done Keyboard
Listing 18.11: Eine virtuelle Methode mit Implementierung »= 0« ist abstrakt.
Book listing lst-0481-book.cpp:
// https://godbolt.org/z/G1q964f1M
#include <iostream> // cout
#include <memory> // unique_ptr
using std::cout;
class Driver { // abstrakte Basisklasse
public:
virtual void init() = 0;
virtual void done() = 0;
virtual void send(const std::string &data) = 0;
};
class ProductionDriver : public Driver {
public:
void init() override { }
void done() override { }
void send(const std::string &data) override { cout << data << "\n"; }
};
class DebuggingDriver : public Driver {
size_t countSend_ = 0;
public:
void init() override {
countSend_= 0; cout << "Ok, bin initialisiert.\n";
}
void done() override {
cout << "send benutzt:" << countSend_ << " mal\n";
}
void send(const std::string &data) override {
cout << "send("<<countSend_<<"):"<< data << "\n";
++countSend_;
}
};
struct DriverWrapper { // RAII-Wrapper für init() und done()
Driver &driver_;
explicit DriverWrapper(Driver& driver) : driver_(driver) { driver_.init(); }
~DriverWrapper() { driver_.done(); }
DriverWrapper(const DriverWrapper&) = delete; // nicht kopieren
};
void doWork(Driver &driver) { // jemand, der flexibel einen beliebigen Driver nutzt
DriverWrapper wrapper(driver); // init() und done() aufrufen
driver.send("Eine unerwartete Reise");
driver.send("Smaugs Einoede");
}
int main() {
// gleiche doWork, einmal mit Produktions- und einmal mit Debugging-Treiber
ProductionDriver production{};
doWork( production );
DebuggingDriver debugging{};
doWork( debugging );
// üblichere Variante eines dynamisch erzeugten Treibers
std::unique_ptr<Driver> driver{ new ProductionDriver{} };
doWork( *driver );
}
Godbolt Listing lst-0481-godb.cpp, https://godbolt.org/z/G1q964f1M:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/G1q964f1M
#include <iostream> // cout
#include <memory> // unique_ptr
using std::cout;
class Driver { // abstrakte Basisklasse
public:
virtual void init() = 0;
virtual void done() = 0;
virtual void send(const std::string &data) = 0;
};
class ProductionDriver : public Driver {
public:
void init() override { }
void done() override { }
void send(const std::string &data) override { cout << data << "\n"; }
};
class DebuggingDriver : public Driver {
size_t countSend_ = 0;
public:
void init() override {
countSend_= 0; cout << "Ok, bin initialisiert.\n";
}
void done() override {
cout << "send benutzt:" << countSend_ << " mal\n";
}
void send(const std::string &data) override {
cout << "send("<<countSend_<<"):"<< data << "\n";
++countSend_;
}
};
struct DriverWrapper { // RAII-Wrapper für init() und done()
Driver &driver_;
explicit DriverWrapper(Driver& driver) : driver_(driver) { driver_.init(); }
~DriverWrapper() { driver_.done(); }
DriverWrapper(const DriverWrapper&) = delete; // nicht kopieren
};
void doWork(Driver &driver) { // jemand, der flexibel einen beliebigen Driver nutzt
DriverWrapper wrapper(driver); // init() und done() aufrufen
driver.send("Eine unerwartete Reise");
driver.send("Smaugs Einoede");
}
int main() {
// gleiche doWork, einmal mit Produktions- und einmal mit Debugging-Treiber
ProductionDriver production{};
doWork( production );
DebuggingDriver debugging{};
doWork( debugging );
// üblichere Variante eines dynamisch erzeugten Treibers
std::unique_ptr<Driver> driver{ new ProductionDriver{} };
doWork( *driver );
}
Listing 18.12: Multiple Vererbung heißt, mehrere Basisklassen zu haben.
Book listing lst-0483-book.cpp:
// https://godbolt.org/z/MPaYW1v5j
#include <iostream>
using std::cout;
class Saeugetier {
public:
void gebaere() { cout << "Geburt!\n"; }
};
class Fliegend {
public:
void fliege() { cout << "Flug!\n"; }
};
class Fledermaus: public Saeugetier, public Fliegend {
public:
void rufe() { cout << "Ultraschall!\n"; }
};
int main() {
Fledermaus bruce{};
bruce.gebaere(); // Ausgabe: Geburt!
bruce.fliege(); // Ausgabe: Flug!
bruce.rufe(); // Ausgabe: Ultraschall!
}
Godbolt Listing lst-0483-godb.cpp, https://godbolt.org/z/MPaYW1v5j:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/MPaYW1v5j
#include <iostream>
using std::cout;
class Saeugetier {
public:
void gebaere() { cout << "Geburt!\n"; }
};
class Fliegend {
public:
void fliege() { cout << "Flug!\n"; }
};
class Fledermaus: public Saeugetier, public Fliegend {
public:
void rufe() { cout << "Ultraschall!\n"; }
};
int main() {
Fledermaus bruce{};
bruce.gebaere(); // Ausgabe: Geburt!
bruce.fliege(); // Ausgabe: Flug!
bruce.rufe(); // Ausgabe: Ultraschall!
}
Listing 18.13: Uhr und Kalender ergeben Uhr mit Kalender.
Book listing lst-0484-book.cpp:
// https://godbolt.org/z/M7TTvaPxx
// Parameter müssen gültige Werte der jeweiligen Einheit sein.
#include <iostream> // ostream
#include <iomanip> // setw, setfill
#include <format>
using std::ostream; using std::format;
class Clock {
protected:
int h_, m_, s_;
public:
Clock(int hours, int minutes, int seconds)
: h_{hours}, m_{minutes}, s_{seconds} {}
void setClock(int hours, int minutes, int seconds) {
h_ = hours; m_ = minutes; s_ = seconds;
}
friend ostream& operator<<(ostream&os, const Clock& c) {
return os << format("{:02}:{:02}:{:02}", c.h_, c.m_, c.s_);
}
void tick() { // +1 Sekunde
if(s_ >= 59) {
s_ = 0;
if(m_ >= 59) {
m_ = 0;
if(h_ >= 23) h_ = 0;
else { h_ += 1; }
} else { m_ += 1; }
} else { s_ += 1; }
}
};
Godbolt Listing lst-0484-godb.cpp, https://godbolt.org/z/M7TTvaPxx:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/M7TTvaPxx
// Parameter müssen gültige Werte der jeweiligen Einheit sein.
#include <iostream> // ostream
#include <iomanip> // setw, setfill
#include <format>
using std::ostream; using std::format;
class Clock {
protected:
int h_, m_, s_;
public:
Clock(int hours, int minutes, int seconds)
: h_{hours}, m_{minutes}, s_{seconds} {}
void setClock(int hours, int minutes, int seconds) {
h_ = hours; m_ = minutes; s_ = seconds;
}
friend ostream& operator<<(ostream&os, const Clock& c) {
return os << format("{:02}:{:02}:{:02}", c.h_, c.m_, c.s_);
}
void tick() { // +1 Sekunde
if(s_ >= 59) {
s_ = 0;
if(m_ >= 59) {
m_ = 0;
if(h_ >= 23) h_ = 0;
else { h_ += 1; }
} else { m_ += 1; }
} else { s_ += 1; }
}
};
GodboltId:a5WxqjxEr
Book listing lst-0485-book.cpp:
// https://godbolt.org/z/a5WxqjxEr
int main() {
Clock clock{ 23, 59, 59 };
std::cout << clock << '\n'; // Ausgabe: 23:59:59
clock.tick();
std::cout << clock << '\n'; // Ausgabe: 00:00:00
}
Godbolt Listing lst-0485-godb.cpp, https://godbolt.org/z/a5WxqjxEr:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/a5WxqjxEr
int main() {
Clock clock{ 23, 59, 59 };
std::cout << clock << '\n'; // Ausgabe: 23:59:59
clock.tick();
std::cout << clock << '\n'; // Ausgabe: 00:00:00
}
Listing 18.14: Eine einfache Kalenderklasse
Book listing lst-0486-book.cpp:
// https://godbolt.org/z/oe1hT9McG
// … includes und usings …
struct Calendar {
int y_, m_, d_;
static const std::vector<int> mlens_;
bool leapyear() const {
if(y_ % 4 != 0) return false;
if(y_ % 100 != 0) return true;
if(y_ % 400 != 0) return false;
return true;
}
public:
Calendar(int year, int month, int day)
: y_{year}, m_{month}, d_{day} {}
void setCalendar(int year, int month, int day) {
y_ = year; m_ = month; d_ = day;
}
friend ostream& operator<<(ostream& os, const Calendar& c) {
return os << format("{:04}-{:02}-{:02}", c.y_, c.m_, c.d_);
}
void advance() { // +1 day
auto maxd = mlens_[m_-1]; // 0-basierter vector
if(m_==2 && leapyear())
maxd += 1; // Februar im Schaltjahr
if(d_ >= maxd) {
d_ = 1;
if(m_ >= 12) { m_ = 1; y_ += 1; }
else { m_ += 1; }
} else { d_ += 1; }
}
};
const std::vector<int> Calendar::mlens_ = {31,28,31,30,31,30,31,31,30,31,30,31};
Godbolt Listing lst-0486-godb.cpp, https://godbolt.org/z/oe1hT9McG:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/oe1hT9McG
// … includes und usings …
struct Calendar {
int y_, m_, d_;
static const std::vector<int> mlens_;
bool leapyear() const {
if(y_ % 4 != 0) return false;
if(y_ % 100 != 0) return true;
if(y_ % 400 != 0) return false;
return true;
}
public:
Calendar(int year, int month, int day)
: y_{year}, m_{month}, d_{day} {}
void setCalendar(int year, int month, int day) {
y_ = year; m_ = month; d_ = day;
}
friend ostream& operator<<(ostream& os, const Calendar& c) {
return os << format("{:04}-{:02}-{:02}", c.y_, c.m_, c.d_);
}
void advance() { // +1 day
auto maxd = mlens_[m_-1]; // 0-basierter vector
if(m_==2 && leapyear())
maxd += 1; // Februar im Schaltjahr
if(d_ >= maxd) {
d_ = 1;
if(m_ >= 12) { m_ = 1; y_ += 1; }
else { m_ += 1; }
} else { d_ += 1; }
}
};
const std::vector<int> Calendar::mlens_ = {31,28,31,30,31,30,31,31,30,31,30,31};
GodboltId:xf1xq8Ts3
Book listing lst-0487-book.cpp:
// https://godbolt.org/z/xf1xq8Ts3
int main() {
Calendar cal{ 2024, 2, 28 };
std::cout << cal << '\n'; // Ausgabe: 2024-02-28
cal.advance();
std::cout << cal << '\n'; // Ausgabe: 2024-02-29
cal.advance();
std::cout << cal << '\n'; // Ausgabe: 2024-03-01
}
Godbolt Listing lst-0487-godb.cpp, https://godbolt.org/z/xf1xq8Ts3:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/xf1xq8Ts3
int main() {
Calendar cal{ 2024, 2, 28 };
std::cout << cal << '\n'; // Ausgabe: 2024-02-28
cal.advance();
std::cout << cal << '\n'; // Ausgabe: 2024-02-29
cal.advance();
std::cout << cal << '\n'; // Ausgabe: 2024-03-01
}
Listing 18.15: Die Kalenderuhr ist ein Kalender und eine Uhr.
Book listing lst-0488-book.cpp:
// https://godbolt.org/z/rh179GW3j
class CalendarClock : public Clock, public Calendar {
public:
CalendarClock(int y, int m, int d, int hh, int mm, int ss)
: Calendar{y,m,d}, Clock{hh,mm,ss} {}
void tick() { // +1 Sekunde
auto prev_h = h_;
Clock::tick(); // Aufruf Basisklassenmethode
if(h_ < prev_h) { // falls neuer Tag
advance(); // … Kalender fortschreiten
}
}
friend ostream& operator<<(ostream&os, const CalendarClock& cc) {
operator<<(os, (Calendar&)cc) << " "; // Aufruf freie Funktion
operator<<(os, (Clock&)cc); // Aufruf freie Funktion
return os;
}
};
Godbolt Listing lst-0488-godb.cpp, https://godbolt.org/z/rh179GW3j:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/rh179GW3j
class CalendarClock : public Clock, public Calendar {
public:
CalendarClock(int y, int m, int d, int hh, int mm, int ss)
: Calendar{y,m,d}, Clock{hh,mm,ss} {}
void tick() { // +1 Sekunde
auto prev_h = h_;
Clock::tick(); // Aufruf Basisklassenmethode
if(h_ < prev_h) { // falls neuer Tag
advance(); // … Kalender fortschreiten
}
}
friend ostream& operator<<(ostream&os, const CalendarClock& cc) {
operator<<(os, (Calendar&)cc) << " "; // Aufruf freie Funktion
operator<<(os, (Clock&)cc); // Aufruf freie Funktion
return os;
}
};
GodboltId:P6nzT7EY4
Book listing lst-0489-book.cpp:
// https://godbolt.org/z/P6nzT7EY4
int main() {
CalendarClock cc{ 2024,2,29, 23,59,59 };
std::cout << cc << '\n'; // Ausgabe: 2024-02-29 23:59:59
cc.tick();
std::cout << cc << '\n'; // Ausgabe: 2024-03-01 00:00:00
}
Godbolt Listing lst-0489-godb.cpp, https://godbolt.org/z/P6nzT7EY4:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/P6nzT7EY4
int main() {
CalendarClock cc{ 2024,2,29, 23,59,59 };
std::cout << cc << '\n'; // Ausgabe: 2024-02-29 23:59:59
cc.tick();
std::cout << cc << '\n'; // Ausgabe: 2024-03-01 00:00:00
}
Listing 18.16: Mit multipler Vererbung kann sich der Wert eines Zeigers ändern.
Book listing lst-0492-book.cpp:
// https://godbolt.org/z/oc7jsbrEK
#include <iostream>
using std::cout;
struct Base1 {
virtual void f1() {}
};
struct Base2 {
virtual void f2() {}
};
struct Derived : public Base1, public Base2 {
virtual void g() {};
};
void vergleich(void* a, void* b) {
cout << (a==b ? "identisch\n" : "unterschiedlich\n");
}
int main() {
Derived d{};
auto *pd = &d;
cout << pd << '\n'; // zum Beispiel 0x1000
auto pb1 = static_cast<Base1*>(pd);
cout << pb1 << '\n'; // immer noch 0x1000
auto pb2 = static_cast<Base2*>(pd);
cout << pb2 << '\n'; // jetzt 0x1008 !
cout << (pd==pb1 ? "gleich\n" : "verschieden\n"); // Ausgabe: gleich
cout << (pd==pb2 ? "gleich\n" : "verschieden\n"); // Ausgabe: gleich
vergleich(pb1, pd); // Ausgabe: identisch
vergleich(pb2, pd); // Ausgabe: unterschiedlich
}
Godbolt Listing lst-0492-godb.cpp, https://godbolt.org/z/oc7jsbrEK:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/oc7jsbrEK
#include <iostream>
using std::cout;
struct Base1 {
virtual void f1() {}
};
struct Base2 {
virtual void f2() {}
};
struct Derived : public Base1, public Base2 {
virtual void g() {};
};
void vergleich(void* a, void* b) {
cout << (a==b ? "identisch\n" : "unterschiedlich\n");
}
int main() {
Derived d{};
auto *pd = &d;
cout << pd << '\n'; // zum Beispiel 0x1000
auto pb1 = static_cast<Base1*>(pd);
cout << pb1 << '\n'; // immer noch 0x1000
auto pb2 = static_cast<Base2*>(pd);
cout << pb2 << '\n'; // jetzt 0x1008 !
cout << (pd==pb1 ? "gleich\n" : "verschieden\n"); // Ausgabe: gleich
cout << (pd==pb2 ? "gleich\n" : "verschieden\n"); // Ausgabe: gleich
vergleich(pb1, pd); // Ausgabe: identisch
vergleich(pb2, pd); // Ausgabe: unterschiedlich
}
Listing 18.17: Das Beobachter-Muster mit multipler Vererbung
Book listing lst-0493-book.cpp:
// https://godbolt.org/z/EnE7Y886M
#include <iostream>
#include <vector>
using std::cout;
// == Beobachter-Entwurfsmuster ==
struct Observer {
virtual void update() = 0;
};
class Subject {
std::vector<Observer*> observers_; // not owning pointers
protected:
void notify() {
for (auto o : observers_)
o->update();
}
public:
void addObserver(Observer* o) {
observers_.push_back(o);
}
};
// == konkrete Klasse ==
struct MyThing {
int calc() { return 1+1; }
};
// == zusammenbringen ==
struct MyObservableThing : public MyThing, public Subject {
int calc() {
notify();
return MyThing::calc();
}
};
// == etwas beobachten ==
struct MyObserver : public Observer {
void update() override {
cout << "observed\n";
}
};
int main() {
MyObserver myObserver{};
MyObservableThing myObservableThing{};
myObservableThing.addObserver(&myObserver);
auto result = myObservableThing.calc(); // Ausgabe: observed
}
Godbolt Listing lst-0493-godb.cpp, https://godbolt.org/z/EnE7Y886M:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/EnE7Y886M
#include <iostream>
#include <vector>
using std::cout;
// == Beobachter-Entwurfsmuster ==
struct Observer {
virtual void update() = 0;
};
class Subject {
std::vector<Observer*> observers_; // not owning pointers
protected:
void notify() {
for (auto o : observers_)
o->update();
}
public:
void addObserver(Observer* o) {
observers_.push_back(o);
}
};
// == konkrete Klasse ==
struct MyThing {
int calc() { return 1+1; }
};
// == zusammenbringen ==
struct MyObservableThing : public MyThing, public Subject {
int calc() {
notify();
return MyThing::calc();
}
};
// == etwas beobachten ==
struct MyObserver : public Observer {
void update() override {
cout << "observed\n";
}
};
int main() {
MyObserver myObserver{};
MyObservableThing myObservableThing{};
myObservableThing.addObserver(&myObserver);
auto result = myObservableThing.calc(); // Ausgabe: observed
}
Listing 18.18: Ein einfaches Beispiel mit virtueller Vererbung
Book listing lst-0494-book.cpp:
// https://godbolt.org/z/8jYeYPs7W
#include <iostream>
using std::cout;
class Base {
public:
int data_ = 0;
};
class Derived1 : public virtual Base {
};
class Derived2 : public virtual Base {
};
class DerivedDerived : public Derived1, public Derived2 {
public:
void method() {
data_ = 1; // eindeutig, denn es gibt nur ein data_
}
};
void ausgabe(const DerivedDerived &dd) {
cout << dd.data_
<< (((Derived1&)dd).data_)
<< (((Derived2&)dd).data_)
<< (((Base&)dd).data_) << '\n';
}
int main() {
DerivedDerived dd{};
ausgabe(dd); // Ausgabe: 0000
dd.method(); // setzt data_ auf 1
ausgabe(dd); // Ausgabe: 1111
}
Godbolt Listing lst-0494-godb.cpp, https://godbolt.org/z/8jYeYPs7W:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/8jYeYPs7W
#include <iostream>
using std::cout;
class Base {
public:
int data_ = 0;
};
class Derived1 : public virtual Base {
};
class Derived2 : public virtual Base {
};
class DerivedDerived : public Derived1, public Derived2 {
public:
void method() {
data_ = 1; // eindeutig, denn es gibt nur ein data_
}
};
void ausgabe(const DerivedDerived &dd) {
cout << dd.data_
<< (((Derived1&)dd).data_)
<< (((Derived2&)dd).data_)
<< (((Base&)dd).data_) << '\n';
}
int main() {
DerivedDerived dd{};
ausgabe(dd); // Ausgabe: 0000
dd.method(); // setzt data_ auf 1
ausgabe(dd); // Ausgabe: 1111
}
Listing 18.19: Effektiv ruft nutzer() hier eine Schwestermethode auf.
Book listing lst-0495-book.cpp:
// https://godbolt.org/z/s9xnn7c5j
#include <iostream>
using std::cout;
struct Base { // abstrakte Klasse
virtual void anbieter() = 0;
virtual void nutzer() = 0;
};
struct Derived1 : public virtual Base { // noch abstrakt
virtual void nutzer() override { anbieter(); }
};
struct Derived2 : public virtual Base { // noch abstrakt
virtual void anbieter() override { cout << "Derived2::anbieter!\n"; }
};
struct DerivedDerived : public Derived1, public Derived2 { // konkret
};
int main() {
DerivedDerived dd{};
DerivedDerived *pdd = ⅆ
Derived1* pd1 = pdd; // Cast innerhalb der Hierarchie
Derived2* pd2 = pdd; // Cast innerhalb der Hierarchie
pdd->nutzer(); // Ausgabe: Derived2::anbieter()!
pd1->nutzer(); // Ausgabe: Derived2::anbieter()!
pd2->nutzer(); // Ausgabe: Derived2::anbieter()!
}
Godbolt Listing lst-0495-godb.cpp, https://godbolt.org/z/s9xnn7c5j:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/s9xnn7c5j
#include <iostream>
using std::cout;
struct Base { // abstrakte Klasse
virtual void anbieter() = 0;
virtual void nutzer() = 0;
};
struct Derived1 : public virtual Base { // noch abstrakt
virtual void nutzer() override { anbieter(); }
};
struct Derived2 : public virtual Base { // noch abstrakt
virtual void anbieter() override { cout << "Derived2::anbieter!\n"; }
};
struct DerivedDerived : public Derived1, public Derived2 { // konkret
};
int main() {
DerivedDerived dd{};
DerivedDerived *pdd = ⅆ
Derived1* pd1 = pdd; // Cast innerhalb der Hierarchie
Derived2* pd2 = pdd; // Cast innerhalb der Hierarchie
pdd->nutzer(); // Ausgabe: Derived2::anbieter()!
pd1->nutzer(); // Ausgabe: Derived2::anbieter()!
pd2->nutzer(); // Ausgabe: Derived2::anbieter()!
}
Listing 18.20: Einen literalen Datentyp erstellen Sie mit einem constexpr-Konstruktor.
Book listing lst-0498-book.cpp:
// https://godbolt.org/z/Kvfx9Yeox
#include <array>
class Value {
int val_;
public:
constexpr Value(int val) : val_{val} {};
constexpr int get() const { return val_; }
};
constexpr Value fuenf{5}; // geht, Value ist literaler Datentyp
std::array<int,fuenf.get()> data; // geht, get ist constexpr
Godbolt Listing lst-0498-godb.cpp, https://godbolt.org/z/Kvfx9Yeox:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Kvfx9Yeox
#include <array>
class Value {
int val_;
public:
constexpr Value(int val) : val_{val} {};
constexpr int get() const { return val_; }
};
constexpr Value fuenf{5}; // geht, Value ist literaler Datentyp
std::array<int,fuenf.get()> data; // geht, get ist constexpr
Listing 18.21: Benutzerdefinierte Literale sind besonders nützlich mit literalen Datentypen.
Book listing lst-0499-book.cpp:
// https://godbolt.org/z/r1vYc7r5j
#include <array>
#include <iostream>
#include <type_traits> // is_literal_type
class Value {
int val_;
public:
constexpr Value(int val) : val_{val} {};
constexpr operator int() const { return val_; }
};
namespace lit {
constexpr Value operator"" _val(const char*, size_t sz) {
return Value(sz); }
}
struct Nope {
constexpr Nope() {};
virtual ~Nope() {}; // nicht trivialer Destruktor
};
int main() {
using namespace lit;
constexpr Value fuenf{5};
std::array<int,"11111"_val> data; // benutzerdefiniertes Literal verwenden
std::cout << data.size() << '\n'; // Ausgabe: 5
std::cout << std::boolalpha;
std::cout << std::is_literal_type<Value>::value << '\n'; // Ausgabe: true
std::cout << std::is_literal_type<Nope>::value << '\n'; // Ausgabe: false
}
Godbolt Listing lst-0499-godb.cpp, https://godbolt.org/z/r1vYc7r5j:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/r1vYc7r5j
#include <array>
#include <iostream>
#include <type_traits> // is_literal_type
class Value {
int val_;
public:
constexpr Value(int val) : val_{val} {};
constexpr operator int() const { return val_; }
};
namespace lit {
constexpr Value operator"" _val(const char*, size_t sz) {
return Value(sz); }
}
struct Nope {
constexpr Nope() {};
virtual ~Nope() {}; // nicht trivialer Destruktor
};
int main() {
using namespace lit;
constexpr Value fuenf{5};
std::array<int,"11111"_val> data; // benutzerdefiniertes Literal verwenden
std::cout << data.size() << '\n'; // Ausgabe: 5
std::cout << std::boolalpha;
std::cout << std::is_literal_type<Value>::value << '\n'; // Ausgabe: true
std::cout << std::is_literal_type<Nope>::value << '\n'; // Ausgabe: false
}
Listing 19.1: Call-by-Reference als Basis für Polymorphie
Book listing lst-0501-book.cpp:
// https://godbolt.org/z/scqTWvhsv
class Auto { };
class VwBulli : public Auto { };
class Ente : public Auto { };
void lassFahren(Auto wagen) { } // (ERR) Wertparameter kopiert nur Basisklasse
void lassBremsen(Auto &wagen) { } // Referenzparameter
void lassHupen(Auto *wagen) { } // Übergabe als Zeiger
int main() {
VwBulli bulli{ }; // automatische Variable
Auto *ente = new Ente{ }; // dynamisch verwaltet
lassFahren(bulli); // (ERR) wird zum Auto kopiert
lassFahren(*ente); // (ERR) wird zum Auto kopiert
lassBremsen(bulli); // bleibt VwBulli
lassBremsen(*ente); // bleibt Ente
lassHupen(&bulli); // bleibt VwBulli
lassHupen(ente); // bleibt Ente
}
Godbolt Listing lst-0501-godb.cpp, https://godbolt.org/z/scqTWvhsv:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/scqTWvhsv
class Auto { };
class VwBulli : public Auto { };
class Ente : public Auto { };
void lassFahren(Auto wagen) { } // (ERR) Wertparameter kopiert nur Basisklasse
void lassBremsen(Auto &wagen) { } // Referenzparameter
void lassHupen(Auto *wagen) { } // Übergabe als Zeiger
int main() {
VwBulli bulli{ }; // automatische Variable
Auto *ente = new Ente{ }; // dynamisch verwaltet
lassFahren(bulli); // (ERR) wird zum Auto kopiert
lassFahren(*ente); // (ERR) wird zum Auto kopiert
lassBremsen(bulli); // bleibt VwBulli
lassBremsen(*ente); // bleibt Ente
lassHupen(&bulli); // bleibt VwBulli
lassHupen(ente); // bleibt Ente
}
Listing 19.2: Die Klasse Buch dient den Akteuren Leser und Bibliothekar.
Book listing lst-0502-book.cpp:
// https://godbolt.org/z/fdh4n5x84
struct Buch {
auto getTitel() { return Titel{"Das C++ Handbuch"s}; }
auto getAutor() { return Autor{"Torsten T. Will"s}; }
auto umblaettern() { return /* Referenz zur nächsten Seite */ 42; }
auto getSeite() { return "aktueller Seiteninhalt"; }
auto getStandort() { return /* Regalnummer/Buchnummer */ 73; }
};
Godbolt Listing lst-0502-godb.cpp, https://godbolt.org/z/fdh4n5x84:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/fdh4n5x84
struct Buch {
auto getTitel() { return Titel{"Das C++ Handbuch"s}; }
auto getAutor() { return Autor{"Torsten T. Will"s}; }
auto umblaettern() { return /* Referenz zur nächsten Seite */ 42; }
auto getSeite() { return "aktueller Seiteninhalt"; }
auto getStandort() { return /* Regalnummer/Buchnummer */ 73; }
};
Listing 19.3: Die Änderungen eines Akteurs spielen sich meist nur noch in einer Klasse ab.
Book listing lst-0503-book.cpp:
// https://godbolt.org/z/Tq9xbGxs4
struct Buch {
auto getTitel() { return Titel{"Das C++ Handbuch"s}; }
auto getAutor() { return Autor{"Torsten T. Will"s}; }
auto umblaettern() { return /* Referenz zur nächsten Seite */ 42; }
auto getSeite() { return "aktueller Seiteninhalt"; }
auto getStandort() { return /* Regalnummer/Buchnummer */ 73; }
};
struct BuchFinder {
Katalog katalog;
auto finde(Buch& buch) { /* Regalnummer/Buchnummer */
katalog.findeBuchNach(buch.getTitel(), buch.getAutor());
}
};
Godbolt Listing lst-0503-godb.cpp, https://godbolt.org/z/Tq9xbGxs4:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Tq9xbGxs4
struct Buch {
auto getTitel() { return Titel{"Das C++ Handbuch"s}; }
auto getAutor() { return Autor{"Torsten T. Will"s}; }
auto umblaettern() { return /* Referenz zur nächsten Seite */ 42; }
auto getSeite() { return "aktueller Seiteninhalt"; }
auto getStandort() { return /* Regalnummer/Buchnummer */ 73; }
};
struct BuchFinder {
Katalog katalog;
auto finde(Buch& buch) { /* Regalnummer/Buchnummer */
katalog.findeBuchNach(buch.getTitel(), buch.getAutor());
}
};
Listing 19.4: Folgt nicht dem Open/Closed Principle
Book listing lst-0504-book.cpp:
// https://godbolt.org/z/vxTsveGjT
#include <vector>
#include <memory> // unique_ptr
#include <iostream> // cout
enum class ShapeTag { CIRC, RECT };
struct Shape { // Data
ShapeTag tag_;
double v1_, v2_;
Shape(double w, double h) : tag_{ShapeTag::RECT}, v1_{w}, v2_{h} {}
Shape(double r) : tag_{ShapeTag::CIRC}, v1_{r}, v2_{0} {}
};
class AreaCalculator { // Logic
public:
double area(const std::vector<std::unique_ptr<Shape>> &shapes) const {
double result = 0;
for(auto &shape : shapes) {
switch(shape->tag_) {
case ShapeTag::CIRC:
result += 3.1415 * shape->v1_ * shape->v1_;
break;
case ShapeTag::RECT:
result += shape->v1_*shape->v2_;
break;
}
}
return result;
}
};
int main() {
std::vector<std::unique_ptr<Shape>> data{};
data.push_back(std::make_unique<Shape>(10.)); // ein Kreis
data.push_back(std::make_unique<Shape>(4., 6.)); // ein Rechteck
// rechnen
AreaCalculator calc{};
std::cout << calc.area( data ) << "\n";
}
Godbolt Listing lst-0504-godb.cpp, https://godbolt.org/z/vxTsveGjT:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/vxTsveGjT
#include <vector>
#include <memory> // unique_ptr
#include <iostream> // cout
enum class ShapeTag { CIRC, RECT };
struct Shape { // Data
ShapeTag tag_;
double v1_, v2_;
Shape(double w, double h) : tag_{ShapeTag::RECT}, v1_{w}, v2_{h} {}
Shape(double r) : tag_{ShapeTag::CIRC}, v1_{r}, v2_{0} {}
};
class AreaCalculator { // Logic
public:
double area(const std::vector<std::unique_ptr<Shape>> &shapes) const {
double result = 0;
for(auto &shape : shapes) {
switch(shape->tag_) {
case ShapeTag::CIRC:
result += 3.1415 * shape->v1_ * shape->v1_;
break;
case ShapeTag::RECT:
result += shape->v1_*shape->v2_;
break;
}
}
return result;
}
};
int main() {
std::vector<std::unique_ptr<Shape>> data{};
data.push_back(std::make_unique<Shape>(10.)); // ein Kreis
data.push_back(std::make_unique<Shape>(4., 6.)); // ein Rechteck
// rechnen
AreaCalculator calc{};
std::cout << calc.area( data ) << "\n";
}
Listing 19.5: Folgt dem OCP
Book listing lst-0505-book.cpp:
// https://godbolt.org/z/YWE4bT4zG
#include <vector>
#include <memory> // unique_ptr
#include <iostream> // cout
struct Shape {
virtual ~Shape() {}
virtual double area() const = 0; // abstrakt
};
class Rectangle : public Shape {
double w_, h_;
public:
Rectangle(double w, double h) : w_{w}, h_{h} {}
double area() const override { return w_ * h_; }
};
class Circle : public Shape {
double r_;
public:
Circle(double r) : r_{r} {}
double area() const override { return 3.1415*r_* r_; }
};
class AreaCalculator { // Logic
public:
double area(const std::vector<std::unique_ptr<Shape>> &shapes) const {
double result = 0;
for(auto &shape : shapes) {
result += shape->area();
}
return result;
}
};
int main() {
std::vector<std::unique_ptr<Shape>> data{};
data.push_back(std::make_unique<Circle>(10.)); // ein Kreis
data.push_back(std::make_unique<Rectangle>(4., 6.)); // ein Rechteck
// rechnen
AreaCalculator calc{};
std::cout << calc.area( data ) << "\n";
}
Godbolt Listing lst-0505-godb.cpp, https://godbolt.org/z/YWE4bT4zG:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/YWE4bT4zG
#include <vector>
#include <memory> // unique_ptr
#include <iostream> // cout
struct Shape {
virtual ~Shape() {}
virtual double area() const = 0; // abstrakt
};
class Rectangle : public Shape {
double w_, h_;
public:
Rectangle(double w, double h) : w_{w}, h_{h} {}
double area() const override { return w_ * h_; }
};
class Circle : public Shape {
double r_;
public:
Circle(double r) : r_{r} {}
double area() const override { return 3.1415*r_* r_; }
};
class AreaCalculator { // Logic
public:
double area(const std::vector<std::unique_ptr<Shape>> &shapes) const {
double result = 0;
for(auto &shape : shapes) {
result += shape->area();
}
return result;
}
};
int main() {
std::vector<std::unique_ptr<Shape>> data{};
data.push_back(std::make_unique<Circle>(10.)); // ein Kreis
data.push_back(std::make_unique<Rectangle>(4., 6.)); // ein Rechteck
// rechnen
AreaCalculator calc{};
std::cout << calc.area( data ) << "\n";
}
GodboltId:rc67xWWfT
Book listing lst-0506-book.cpp:
// https://godbolt.org/z/rc67xWWfT
#include <iostream>
struct Point { int x, y; };
class Rectangle {
protected:
Point origin_; int width_; int height_;
public:
Rectangle(Point o, int w, int h) : origin_{o}, width_{w}, height_{h} {}
virtual void setHeight(int height) { height_ = height; }
virtual int getHeight() const { return height_; }
virtual void setWidth(int width) { width_ = width; }
virtual int getWidth() const { return width_; }
virtual int getArea() const { return width_ * height_; }
};
class Square : public Rectangle {
public:
Square(Point o, int wh) : Rectangle{o, wh, wh} {}
void setHeight(int wh) override { width_ = height_ = wh; }
void setWidth(int wh) override { width_ = height_ = wh; }
};
void areaCheck(Rectangle &rect) {
rect.setWidth(5);
rect.setHeight(4);
auto areaValue = rect.getArea();
if(areaValue != 20) {
std::cout << "error!\n";
} else {
std::cout << "all fine\n";
}
}
int main() {
Rectangle rect{ {0,0}, 0,0 };
areaCheck( rect ); // Ausgabe: all fine
Square square{ {0,0}, 0 };
areaCheck( square ); // Ausgabe: error!
}
Godbolt Listing lst-0506-godb.cpp, https://godbolt.org/z/rc67xWWfT:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/rc67xWWfT
#include <iostream>
struct Point { int x, y; };
class Rectangle {
protected:
Point origin_; int width_; int height_;
public:
Rectangle(Point o, int w, int h) : origin_{o}, width_{w}, height_{h} {}
virtual void setHeight(int height) { height_ = height; }
virtual int getHeight() const { return height_; }
virtual void setWidth(int width) { width_ = width; }
virtual int getWidth() const { return width_; }
virtual int getArea() const { return width_ * height_; }
};
class Square : public Rectangle {
public:
Square(Point o, int wh) : Rectangle{o, wh, wh} {}
void setHeight(int wh) override { width_ = height_ = wh; }
void setWidth(int wh) override { width_ = height_ = wh; }
};
void areaCheck(Rectangle &rect) {
rect.setWidth(5);
rect.setHeight(4);
auto areaValue = rect.getArea();
if(areaValue != 20) {
std::cout << "error!\n";
} else {
std::cout << "all fine\n";
}
}
int main() {
Rectangle rect{ {0,0}, 0,0 };
areaCheck( rect ); // Ausgabe: all fine
Square square{ {0,0}, 0 };
areaCheck( square ); // Ausgabe: error!
}
Listing 19.6: Kovarianz für Rückgabetypen
Book listing lst-0507-book.cpp:
// https://godbolt.org/z/Gxh4edc8n
using std::vector;
struct B {};
struct D : public B {};
struct Base1 {
virtual B& func();
};
struct Derived1 : public Base1 {
virtual D& func() override; // D& ist kovariant
};
struct Base2 {
virtual B& func();
};
struct Derived2 : public Base2 {
virtual D func() override; // (ERR) D ist nicht kovariant
};
struct Base3 {
virtual vector<B> func();
};
struct Derived3 : public Base3 {
virtual vector<D>& func() override; // (ERR) vector<D>& ist nicht kovariant
};
struct Base4 {
virtual vector<B*>& func();
};
struct Derived4 : public Base4 {
virtual vector<D*>& func() override; // (ERR) anderer Typ, nicht kovariant
};
Godbolt Listing lst-0507-godb.cpp, https://godbolt.org/z/Gxh4edc8n:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Gxh4edc8n
using std::vector;
struct B {};
struct D : public B {};
struct Base1 {
virtual B& func();
};
struct Derived1 : public Base1 {
virtual D& func() override; // D& ist kovariant
};
struct Base2 {
virtual B& func();
};
struct Derived2 : public Base2 {
virtual D func() override; // (ERR) D ist nicht kovariant
};
struct Base3 {
virtual vector<B> func();
};
struct Derived3 : public Base3 {
virtual vector<D>& func() override; // (ERR) vector<D>& ist nicht kovariant
};
struct Base4 {
virtual vector<B*>& func();
};
struct Derived4 : public Base4 {
virtual vector<D*>& func() override; // (ERR) anderer Typ, nicht kovariant
};
GodboltId:4536hxvEK
Book listing lst-0510-book.cpp:
// https://godbolt.org/z/4536hxvEK
int value = 42;
int& valueRef = value; // Referenz; kein Adressoperator & nötig
valueRef = 18; // kein Dereferenzierungsoperator * nötig
cout << value << "\n"; // Ausgabe: 18
Godbolt Listing lst-0510-godb.cpp, https://godbolt.org/z/4536hxvEK:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/4536hxvEK
int value = 42;
int& valueRef = value; // Referenz; kein Adressoperator & nötig
valueRef = 18; // kein Dereferenzierungsoperator * nötig
cout << value << "\n"; // Ausgabe: 18
Listing 20.1: Zeiger können im Laufe ihres Lebens neue Adressen zugewiesen bekommen.
Book listing lst-0511-book.cpp:
// https://godbolt.org/z/qTxs8bTdz
#include <vector>
#include <iostream>
using std::vector; using std::cout; using std::ostream;
ostream& printVector(ostream& os, const vector<int> &arg) { // Hilfsfunktion
for(int w : arg) os << w << " "; return os;
}
int main() {
vector<int> werte{ };
werte.reserve(50); // Platz für 50 Werte garantieren
int *groesstes = nullptr; // mit besonderem Wert initialisieren
for(int w : { 20, 2, 30, 15, 81, 104, 70, 2, }) {
werte.push_back(w);
if(!groesstes || *groesstes < w ) { // dereferenzieren zum Wert
groesstes = &(werte.back()); // neue Adresse merken; deshalb nicht '*'
}
}
printVector(cout, werte) << "\n"; // Ausgabe: 20 2 30 15 81 104 70 2
// groesstes enthält nun die Adresse der 104:
*groesstes = -999; // dereferenzieren; also Wert überschreiben
printVector(cout, werte) << "\n"; // Ausgabe: 20 2 30 15 81 –999 70 2
}
Godbolt Listing lst-0511-godb.cpp, https://godbolt.org/z/qTxs8bTdz:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/qTxs8bTdz
#include <vector>
#include <iostream>
using std::vector; using std::cout; using std::ostream;
ostream& printVector(ostream& os, const vector<int> &arg) { // Hilfsfunktion
for(int w : arg) os << w << " "; return os;
}
int main() {
vector<int> werte{ };
werte.reserve(50); // Platz für 50 Werte garantieren
int *groesstes = nullptr; // mit besonderem Wert initialisieren
for(int w : { 20, 2, 30, 15, 81, 104, 70, 2, }) {
werte.push_back(w);
if(!groesstes || *groesstes < w ) { // dereferenzieren zum Wert
groesstes = &(werte.back()); // neue Adresse merken; deshalb nicht '*'
}
}
printVector(cout, werte) << "\n"; // Ausgabe: 20 2 30 15 81 104 70 2
// groesstes enthält nun die Adresse der 104:
*groesstes = -999; // dereferenzieren; also Wert überschreiben
printVector(cout, werte) << "\n"; // Ausgabe: 20 2 30 15 81 –999 70 2
}
Listing 20.2: Eine Rückgabe als Wert kann eine Kopie erzeugen.
Book listing lst-0514-book.cpp:
Planet erzeugePlanet(const Event &evt) { // Rückgabe als Wert
Planet result{"Erde"}; // Stackobjekt
result.setLocation(evt.getPosition());
return result; // Rückgabe erzeugt (potenziell) Kopie
}
Listing 20.3: Eine Rückgabe als Zeiger kopiert nur den Zeiger, nicht das Objekt.
Book listing lst-0515-book.cpp:
// Rückgabe als (smarter) Pointer:
unique_ptr<Planet> erzeugePlanet(const Event &evt) {
unique_ptr<Planet> result{ new Planet{"Venus"} }; // Heapobjekt
result->setLocation(evt.getPosition());
return result; // reicht Adresse weiter
}
Listing 20.4: In den folgenden Beispielen verwende ich Image als Klasse, zu der ich einen Zeiger haben will.
Book listing lst-0517-book.cpp:
// https://godbolt.org/z/ehhGPjabz
#include <string>
#include <vector>
class Image {
std::vector<char> bilddaten_;
public:
explicit Image(const std::string& filename) { /* Bild laden */ }
void draw() const { /* Bild malen */ };
};
Godbolt Listing lst-0517-godb.cpp, https://godbolt.org/z/ehhGPjabz:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/ehhGPjabz
#include <string>
#include <vector>
class Image {
std::vector<char> bilddaten_;
public:
explicit Image(const std::string& filename) { /* Bild laden */ }
void draw() const { /* Bild malen */ };
};
Listing 20.5: unique_ptr als Datenfeld, Rückgabewert und lokale Variable
Book listing lst-0518-book.cpp:
// https://godbolt.org/z/Eh9ox6x9E
#include <memory> // unique_ptr
#include <string>
#include <iostream>
using std::unique_ptr; using std::string;
class Component { }; // Dummy-Fensterhierarchie
class Label : public Component { };
class Textfield : public Component { };
class Button : public Component {
public:
int id_; // ID zur Unterscheidung der Buttons
explicit Button(int id) : id_{id} {}
};
class Window { };
class MyDialog : public Window {
string title_;
unique_ptr<Label> lblVorname_{new Label{}}; // lauter Datenfelder
unique_ptr<Textfield> txtVorname_{new Textfield{}}; // … an die Lebensdauer
unique_ptr<Label> lblNachname_{new Label{}}; // … der Klasse gebunden
unique_ptr<Textfield> txtNachname_{new Textfield{}};
unique_ptr<Button> btnOk_{new Button{1}};
unique_ptr<Button> btnAbbrechen_{new Button{2}};
public:
explicit MyDialog(const string& title) : title_{title} {}
unique_ptr<Button> showModal()
{ return std::move(btnOk_); } // Platzhaltercode; OK gedrückt
};
unique_ptr<MyDialog> createDialog() {
return unique_ptr<MyDialog>{ // temporärer Wert
new MyDialog{"Bitte Namen eingeben"}};
}
int showDialog() {
unique_ptr<MyDialog> dialog = createDialog(); // lokale Variable
unique_ptr<Button> gedrueckt = dialog->showModal(); // Rückgabewert
return gedrueckt->id_;
}
int main() {
int gedrueckt_id = showDialog();
if(gedrueckt_id == 1) {
std::cout << "Danke, dass Sie OK gedrueckt haben\n";
}
}
Godbolt Listing lst-0518-godb.cpp, https://godbolt.org/z/Eh9ox6x9E:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Eh9ox6x9E
#include <memory> // unique_ptr
#include <string>
#include <iostream>
using std::unique_ptr; using std::string;
class Component { }; // Dummy-Fensterhierarchie
class Label : public Component { };
class Textfield : public Component { };
class Button : public Component {
public:
int id_; // ID zur Unterscheidung der Buttons
explicit Button(int id) : id_{id} {}
};
class Window { };
class MyDialog : public Window {
string title_;
unique_ptr<Label> lblVorname_{new Label{}}; // lauter Datenfelder
unique_ptr<Textfield> txtVorname_{new Textfield{}}; // … an die Lebensdauer
unique_ptr<Label> lblNachname_{new Label{}}; // … der Klasse gebunden
unique_ptr<Textfield> txtNachname_{new Textfield{}};
unique_ptr<Button> btnOk_{new Button{1}};
unique_ptr<Button> btnAbbrechen_{new Button{2}};
public:
explicit MyDialog(const string& title) : title_{title} {}
unique_ptr<Button> showModal()
{ return std::move(btnOk_); } // Platzhaltercode; OK gedrückt
};
unique_ptr<MyDialog> createDialog() {
return unique_ptr<MyDialog>{ // temporärer Wert
new MyDialog{"Bitte Namen eingeben"}};
}
int showDialog() {
unique_ptr<MyDialog> dialog = createDialog(); // lokale Variable
unique_ptr<Button> gedrueckt = dialog->showModal(); // Rückgabewert
return gedrueckt->id_;
}
int main() {
int gedrueckt_id = showDialog();
if(gedrueckt_id == 1) {
std::cout << "Danke, dass Sie OK gedrueckt haben\n";
}
}
Listing 20.6: Ein Spielfeld mit lauter verschiedenen Objekten.
Book listing lst-0520-book.cpp:
// https://godbolt.org/z/sas3b1E3b
#include <vector>
#include <iostream>
#include <memory> // shared_ptr
#include <random> // uniform_int_distribution, random_device
namespace { // Beginn des anonymen Namensraums
using std::shared_ptr; using std::make_shared;
using std::vector; using std::cout;
struct Asteroid {
int points_ = 100;
int structure_ = 10;
};
struct Ship {
shared_ptr<Asteroid> firedLastOn_{};
int score_ = 0;
int firepower = 1;
bool fireUpon(shared_ptr<Asteroid> a);
};
struct GameBoard {
vector<shared_ptr<Asteroid>> asteroids_;
explicit GameBoard(int nAsteroids);
bool shipFires(Ship& ship);
};
// Implementierung von Ship
bool Ship::fireUpon(shared_ptr<Asteroid> a) {
if(!a) return false; // ungültiger Asteroid
a->structure_ -= firepower;
if(a.get() == firedLastOn_.get())
firepower *= 2 ; // Schaden vergrößern
else
firepower = 1; // zurücksetzen
firedLastOn_ = a;
return a->structure_ <= 0; // kaputt?
}
// Implementierung von GameBoard
GameBoard::GameBoard(int nAsteroids) : asteroids_{}
{ // einige Standard-Asteroiden
for(int idx=0; idx<nAsteroids; ++idx)
asteroids_.push_back( make_shared<Asteroid>() );
}
int wuerfel(int min, int max) {
/* static std::default_random_engine e{}; */ // Pseudozufallsgenerator
static std::random_device e{}; // Zufallsgenerator
return std::uniform_int_distribution<int>{min, max}(e); // würfeln
}
bool GameBoard::shipFires(Ship &ship) {
int idx = wuerfel(0, asteroids_.size()-1);
bool kaputt = ship.fireUpon(asteroids_[idx]);
if(kaputt) {
ship.score_ += asteroids_[idx]->points_;
asteroids_.erase(asteroids_.begin()+idx); // entfernen
}
return asteroids_.size() == 0; // alles kaputt
}
} // Ende des anonymen Namensraums
int main() {
GameBoard game{10}; // 10 Asteroiden
Ship ship{};
for(int idx = 0; idx < 85; ++idx) { // 85 Schüsse
if(game.shipFires(ship)) {
cout << "Der Weltraum ist nach " << idx+1 << " Schuessen leer. ";
break;
}
}
cout << "Sie haben " << ship.score_ << " Punkte erreicht.\n";
}
Godbolt Listing lst-0520-godb.cpp, https://godbolt.org/z/sas3b1E3b:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/sas3b1E3b
#include <vector>
#include <iostream>
#include <memory> // shared_ptr
#include <random> // uniform_int_distribution, random_device
namespace { // Beginn des anonymen Namensraums
using std::shared_ptr; using std::make_shared;
using std::vector; using std::cout;
struct Asteroid {
int points_ = 100;
int structure_ = 10;
};
struct Ship {
shared_ptr<Asteroid> firedLastOn_{};
int score_ = 0;
int firepower = 1;
bool fireUpon(shared_ptr<Asteroid> a);
};
struct GameBoard {
vector<shared_ptr<Asteroid>> asteroids_;
explicit GameBoard(int nAsteroids);
bool shipFires(Ship& ship);
};
// Implementierung von Ship
bool Ship::fireUpon(shared_ptr<Asteroid> a) {
if(!a) return false; // ungültiger Asteroid
a->structure_ -= firepower;
if(a.get() == firedLastOn_.get())
firepower *= 2 ; // Schaden vergrößern
else
firepower = 1; // zurücksetzen
firedLastOn_ = a;
return a->structure_ <= 0; // kaputt?
}
// Implementierung von GameBoard
GameBoard::GameBoard(int nAsteroids) : asteroids_{}
{ // einige Standard-Asteroiden
for(int idx=0; idx<nAsteroids; ++idx)
asteroids_.push_back( make_shared<Asteroid>() );
}
int wuerfel(int min, int max) {
/* static std::default_random_engine e{}; */ // Pseudozufallsgenerator
static std::random_device e{}; // Zufallsgenerator
return std::uniform_int_distribution<int>{min, max}(e); // würfeln
}
bool GameBoard::shipFires(Ship &ship) {
int idx = wuerfel(0, asteroids_.size()-1);
bool kaputt = ship.fireUpon(asteroids_[idx]);
if(kaputt) {
ship.score_ += asteroids_[idx]->points_;
asteroids_.erase(asteroids_.begin()+idx); // entfernen
}
return asteroids_.size() == 0; // alles kaputt
}
} // Ende des anonymen Namensraums
int main() {
GameBoard game{10}; // 10 Asteroiden
Ship ship{};
for(int idx = 0; idx < 85; ++idx) { // 85 Schüsse
if(game.shipFires(ship)) {
cout << "Der Weltraum ist nach " << idx+1 << " Schuessen leer. ";
break;
}
}
cout << "Sie haben " << ship.score_ << " Punkte erreicht.\n";
}
Listing 20.7: Wenn ein roher Zeiger ein Objekt besitzt, sind die möglichen Fehler oft schwer zu erkennen.
Book listing lst-0523-book.cpp:
// https://godbolt.org/z/Mqrxxs11Y
struct StereoImage {
Image* rechts_; // (ERR) roher Zeiger
Image* links_; // (ERR) roher Zeiger
StereoImage(const string& nameBase) // konstruieren
: rechts_{new Image{nameBase+"rechts.jpg"}} // okay
, links_{new Image{nameBase+"links.jpg"}} // gefährlich
{ }
~StereoImage() { // entfernen
delete rechts_; delete links_;
}
StereoImage(const StereoImage&) = delete; // keine Kopie
StereoImage& operator=(const StereoImage&) = delete; // keine Zuweisung
};
int main() {
Image* bild = new Image{"bild.jpg"}; // (ERR) einem rohen Zeiger?
StereoImage stereo{"3d"};
delete bild;
}
Godbolt Listing lst-0523-godb.cpp, https://godbolt.org/z/Mqrxxs11Y:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Mqrxxs11Y
struct StereoImage {
Image* rechts_; // (ERR) roher Zeiger
Image* links_; // (ERR) roher Zeiger
StereoImage(const string& nameBase) // konstruieren
: rechts_{new Image{nameBase+"rechts.jpg"}} // okay
, links_{new Image{nameBase+"links.jpg"}} // gefährlich
{ }
~StereoImage() { // entfernen
delete rechts_; delete links_;
}
StereoImage(const StereoImage&) = delete; // keine Kopie
StereoImage& operator=(const StereoImage&) = delete; // keine Zuweisung
};
int main() {
Image* bild = new Image{"bild.jpg"}; // (ERR) einem rohen Zeiger?
StereoImage stereo{"3d"};
delete bild;
}
Listing 20.8: prims enthält Zeiger in einen anderen Container.
Book listing lst-0525-book.cpp:
// https://godbolt.org/z/YMe5PY6aT
#include <vector>
#include <numeric> // iota
#include <iostream>
using std::vector; using std::cout;
struct Zahl { // stellvertretend für ein großes, teures Objekt
unsigned long val_;
Zahl(unsigned long val) : val_{val} {}
Zahl() : val_{0} {}
};
/* ermittelt anhand bisheriger Primzahlen, ob z eine Primzahl ist */
bool isPrim(const Zahl& z, const vector<Zahl*> prims) {
for(Zahl* p : prims) {
if((p->val_*p->val_) > z.val_) return true; // zu groß
if(z.val_ % p->val_ == 0) return false; // ist Teiler
}
return true;
}
int main() {
vector<Zahl> alleZahlen(98); // 98 mit null initialisierte Elemente
std::iota(begin(alleZahlen), end(alleZahlen), 3); // 3..100
/* alleZahlen enthält jetzt {3..100} */
vector<Zahl*> prims{}; // bekommt ermittelte Primzahlen
Zahl zwei{2};
prims.push_back(&zwei); // die 2 wird gebraucht
for(Zahl &z : alleZahlen) { // über alle Zahlen iterieren
if(isPrim(z, prims)) {
prims.push_back( &z ); // speichere Adresse
}
}
/* Rest ausgeben */
for(Zahl* p : prims)
cout << p->val_ << " ";
cout << "\n";
}
Godbolt Listing lst-0525-godb.cpp, https://godbolt.org/z/YMe5PY6aT:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/YMe5PY6aT
#include <vector>
#include <numeric> // iota
#include <iostream>
using std::vector; using std::cout;
struct Zahl { // stellvertretend für ein großes, teures Objekt
unsigned long val_;
Zahl(unsigned long val) : val_{val} {}
Zahl() : val_{0} {}
};
/* ermittelt anhand bisheriger Primzahlen, ob z eine Primzahl ist */
bool isPrim(const Zahl& z, const vector<Zahl*> prims) {
for(Zahl* p : prims) {
if((p->val_*p->val_) > z.val_) return true; // zu groß
if(z.val_ % p->val_ == 0) return false; // ist Teiler
}
return true;
}
int main() {
vector<Zahl> alleZahlen(98); // 98 mit null initialisierte Elemente
std::iota(begin(alleZahlen), end(alleZahlen), 3); // 3..100
/* alleZahlen enthält jetzt {3..100} */
vector<Zahl*> prims{}; // bekommt ermittelte Primzahlen
Zahl zwei{2};
prims.push_back(&zwei); // die 2 wird gebraucht
for(Zahl &z : alleZahlen) { // über alle Zahlen iterieren
if(isPrim(z, prims)) {
prims.push_back( &z ); // speichere Adresse
}
}
/* Rest ausgeben */
for(Zahl* p : prims)
cout << p->val_ << " ";
cout << "\n";
}
Listing 20.9: Liefern Sie keine Adressen von funktionslokalen Objekten zurück.
Book listing lst-0528-book.cpp:
vector<Zahl*> primZeiger(unsigned long bis) { // (ERR) Vektor von Zeigern ist verdächtig
vector<Zahl> alleZahlen;
vector<Zahl*> prims{};
// …
for(Zahl &z : alleZahlen)
if(isPrim(z, prims))
prims.push_back( &z ); // speichere Adresse
return prims; // (ERR) Zeiger auf funktionslokale Objekte
}
Listing 20.10: Mit rohen Zeigern, die in ein C-Array zeigen, können Sie rechnen.
Book listing lst-0533-book.cpp:
// https://godbolt.org/z/3zrK76zn8
#include <iostream>
int main() {
int carray[10] = { 1,1 }; // initialisiert zu { 1,1,0,0,0,0,0,0,0,0 }
int* ende = carray+10; // Zeiger hinter das letzte Element
for(int* p =carray+2; p != ende; ++p) {
*p = *(p-1) + *(p-2); // addiert die vorigen beiden Zahlen
}
for(int const * p=carray; p != ende; ++p)
std::cout << *p << " ";
std::cout << "\n";
}
Godbolt Listing lst-0533-godb.cpp, https://godbolt.org/z/3zrK76zn8:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/3zrK76zn8
#include <iostream>
int main() {
int carray[10] = { 1,1 }; // initialisiert zu { 1,1,0,0,0,0,0,0,0,0 }
int* ende = carray+10; // Zeiger hinter das letzte Element
for(int* p =carray+2; p != ende; ++p) {
*p = *(p-1) + *(p-2); // addiert die vorigen beiden Zahlen
}
for(int const * p=carray; p != ende; ++p)
std::cout << *p << " ";
std::cout << "\n";
}
Listing 20.11: C-Arrays verfallen als Parameter zu rohen Zeigern.
Book listing lst-0537-book.cpp:
// https://godbolt.org/z/1qx16Gr61
#include <iostream>
void fibonacci(int data[], int* ende) {
for(int* p = data+2; p != ende; ++p) {
*p = *(p-1) + *(p-2);
}
}
std::ostream& print(std::ostream &os, int data[], int* ende) {
for(int const * p=data; p != ende; ++p)
std::cout << *p << " ";
return os;
}
int main() {
int carray[10] = { 1,1 }; // initialisiert zu { 1,1,0,0,0,0,0,0,0,0 }
fibonacci(carray, carray+10);
print(std::cout, carray, carray+10) << "\n";
}
Godbolt Listing lst-0537-godb.cpp, https://godbolt.org/z/1qx16Gr61:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/1qx16Gr61
#include <iostream>
void fibonacci(int data[], int* ende) {
for(int* p = data+2; p != ende; ++p) {
*p = *(p-1) + *(p-2);
}
}
std::ostream& print(std::ostream &os, int data[], int* ende) {
for(int const * p=data; p != ende; ++p)
std::cout << *p << " ";
return os;
}
int main() {
int carray[10] = { 1,1 }; // initialisiert zu { 1,1,0,0,0,0,0,0,0,0 }
fibonacci(carray, carray+10);
print(std::cout, carray, carray+10) << "\n";
}
Listing 20.12: »unique_ptr« arbeitet mit dem dynamischen C-Array zusammen.
Book listing lst-0541-book.cpp:
// https://godbolt.org/z/MEqcExjrY
#include <memory> // unique_ptr
#include <iostream> // cout
std::unique_ptr<int[]> createData(size_t sz) {
return std::unique_ptr<int[]>(new int[sz]);
}
void fibonacci(int data[], int* ende) {
for(int* p = data+2; p != ende; ++p) {
*p = *(p-1) + *(p-2);
}
}
std::ostream& print(std::ostream &os, int data[], int* ende) {
for(int const* p= data; p != ende; ++p)
std::cout << *p << " ";
return os;
}
int main() {
std::unique_ptr<int[]> data { createData(10) };
data[0] = 1; // setzen Sie Werte im Array durch den unique_ptr
data[1] = 1;
fibonacci(data.get(), data.get()+10); // holen Sie sich den C-Array-Zeiger mit get()
print(std::cout, data.get(), data.get()+10) << "\n";
}
Godbolt Listing lst-0541-godb.cpp, https://godbolt.org/z/MEqcExjrY:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/MEqcExjrY
#include <memory> // unique_ptr
#include <iostream> // cout
std::unique_ptr<int[]> createData(size_t sz) {
return std::unique_ptr<int[]>(new int[sz]);
}
void fibonacci(int data[], int* ende) {
for(int* p = data+2; p != ende; ++p) {
*p = *(p-1) + *(p-2);
}
}
std::ostream& print(std::ostream &os, int data[], int* ende) {
for(int const* p= data; p != ende; ++p)
std::cout << *p << " ";
return os;
}
int main() {
std::unique_ptr<int[]> data { createData(10) };
data[0] = 1; // setzen Sie Werte im Array durch den unique_ptr
data[1] = 1;
fibonacci(data.get(), data.get()+10); // holen Sie sich den C-Array-Zeiger mit get()
print(std::cout, data.get(), data.get()+10) << "\n";
}
GodboltId:s6sss481E
Book listing lst-0545-book.cpp:
// https://godbolt.org/z/s6sss481E
const char vimes[13] = "Samuel Vimes"; // const char[13]
const char colon[] = "Fred Colon"; // const char[11]
const char* nobby = "Nobby Nobbs"; // const char[12]
Godbolt Listing lst-0545-godb.cpp, https://godbolt.org/z/s6sss481E:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/s6sss481E
const char vimes[13] = "Samuel Vimes"; // const char[13]
const char colon[] = "Fred Colon"; // const char[11]
const char* nobby = "Nobby Nobbs"; // const char[12]
Listing 20.13: Mit »string« fällt Ihnen oft gar nicht auf, dass Textliterale »const char[]« sind.
Book listing lst-0546-book.cpp:
// https://godbolt.org/z/oKsz7d55T
#include <string>
#include <iostream> // cout
using std::string; using std::cout;
string greet(string name) {
return name + "!"; // string operator+(string, const char*)
}
int main() {
string name{ "Havaloc Vetinari" }; // explizit: string(const char*)
cout << "Angua"; // ostream& operator<<(ostream&, const char*)
cout << // ostream& operator<<(ostream, string)
greet("Carrot Ironfoundersson"); // implizit: string(const char*)
}
Godbolt Listing lst-0546-godb.cpp, https://godbolt.org/z/oKsz7d55T:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/oKsz7d55T
#include <string>
#include <iostream> // cout
using std::string; using std::cout;
string greet(string name) {
return name + "!"; // string operator+(string, const char*)
}
int main() {
string name{ "Havaloc Vetinari" }; // explizit: string(const char*)
cout << "Angua"; // ostream& operator<<(ostream&, const char*)
cout << // ostream& operator<<(ostream, string)
greet("Carrot Ironfoundersson"); // implizit: string(const char*)
}
Listing 20.14: Iteratoren holen Sie mit »begin« und »end«.
Book listing lst-0547-book.cpp:
// https://godbolt.org/z/4nqz4ed4W
#include <vector>
#include <iostream> // cout
using std::vector;
int main() {
vector data{ 5,4,3,2,1 };
vector<int>::const_iterator ende = data.end(); // oder end(data)
for(vector<int>::const_iterator it = data.begin(); it!=ende; ++it) {
std::cout << *it << " ";
}
std::cout << "\n";
}
Godbolt Listing lst-0547-godb.cpp, https://godbolt.org/z/4nqz4ed4W:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/4nqz4ed4W
#include <vector>
#include <iostream> // cout
using std::vector;
int main() {
vector data{ 5,4,3,2,1 };
vector<int>::const_iterator ende = data.end(); // oder end(data)
for(vector<int>::const_iterator it = data.begin(); it!=ende; ++it) {
std::cout << *it << " ";
}
std::cout << "\n";
}
Listing 20.15: Rohe Zeiger können Sie wie Iteratoren verwenden.
Book listing lst-0548-book.cpp:
// https://godbolt.org/z/zsqKz76cj
#include <iostream> // cout
#include <iterator> // ostream_iterator
#include <algorithm> // copy, ranges::copy
int main () {
int data[6] = { 1, 2, 3, 7, 9, 10 };
std::ostream_iterator<int> out_it (std::cout,", ");
std::copy(data, data+6, out_it); // Zeiger als Iteratoren
std::cout << "\n"; // Ausgabe: 1, 2, 3, 7, 9, 10
std::ranges::copy(data, out_it); // C-Array-Zeiger als Range
std::cout << "\n"; // Ausgabe: 1, 2, 3, 7, 9, 10
}
Godbolt Listing lst-0548-godb.cpp, https://godbolt.org/z/zsqKz76cj:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/zsqKz76cj
#include <iostream> // cout
#include <iterator> // ostream_iterator
#include <algorithm> // copy, ranges::copy
int main () {
int data[6] = { 1, 2, 3, 7, 9, 10 };
std::ostream_iterator<int> out_it (std::cout,", ");
std::copy(data, data+6, out_it); // Zeiger als Iteratoren
std::cout << "\n"; // Ausgabe: 1, 2, 3, 7, 9, 10
std::ranges::copy(data, out_it); // C-Array-Zeiger als Range
std::cout << "\n"; // Ausgabe: 1, 2, 3, 7, 9, 10
}
Listing 20.16: Lohnt es sich, das Freigeben von Speicher zu sparen?
Book listing lst-0549-book.cpp:
// https://godbolt.org/z/M13eYMrjG
#include <map>
#include <memory> // unique_ptr
#include <string>
#include <iostream>
#include <chrono> // Zeitmessung
using std::map; using std::cout; using std::endl; using namespace std::chrono;
struct Node {
std::unique_ptr<int> d_;
Node() : Node{0} { }
explicit Node(int d) : d_{ new int } { *d_ = d; } // auch etwas Speicher
friend bool operator<(const Node& a, const Node& b) {return *a.d_<*b.d_;}
friend bool operator==(const Node& a, const Node& b) {return *a.d_==*b.d_;}
};
long long millisSeit(steady_clock::time_point start) { // Helfer zur Zeitmessung
return duration_cast<milliseconds>(steady_clock::now()-start).count();
}
int main() {
std::unique_ptr<map<int,Node>> riesig{ new map<int,Node>{} };
cout << "Aufbau..." << endl;
steady_clock::time_point start = steady_clock::now();
for(int idx=0; idx < 100*1000*1000; ++idx) { // massive Menge in der map
(*riesig)[idx] = Node{idx};
}
cout << "Fertig: " << millisSeit(start) << " ms" << endl; // Zeitmessung hier
start = steady_clock::now();
riesig.reset(); // wegräumen hier
cout << "Ende: " << millisSeit(start) << " ms" << endl; // Zeitmessung hier
}
Godbolt Listing lst-0549-godb.cpp, https://godbolt.org/z/M13eYMrjG:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/M13eYMrjG
#include <map>
#include <memory> // unique_ptr
#include <string>
#include <iostream>
#include <chrono> // Zeitmessung
using std::map; using std::cout; using std::endl; using namespace std::chrono;
struct Node {
std::unique_ptr<int> d_;
Node() : Node{0} { }
explicit Node(int d) : d_{ new int } { *d_ = d; } // auch etwas Speicher
friend bool operator<(const Node& a, const Node& b) {return *a.d_<*b.d_;}
friend bool operator==(const Node& a, const Node& b) {return *a.d_==*b.d_;}
};
long long millisSeit(steady_clock::time_point start) { // Helfer zur Zeitmessung
return duration_cast<milliseconds>(steady_clock::now()-start).count();
}
int main() {
std::unique_ptr<map<int,Node>> riesig{ new map<int,Node>{} };
cout << "Aufbau..." << endl;
steady_clock::time_point start = steady_clock::now();
for(int idx=0; idx < 100*1000*1000; ++idx) { // massive Menge in der map
(*riesig)[idx] = Node{idx};
}
cout << "Fertig: " << millisSeit(start) << " ms" << endl; // Zeitmessung hier
start = steady_clock::now();
riesig.reset(); // wegräumen hier
cout << "Ende: " << millisSeit(start) << " ms" << endl; // Zeitmessung hier
}
Listing 21.1: Zeilen, die Präprozessordirektiven enthalten, beginnen mit einem #.
Book listing lst-0551-book.cpp:
// https://godbolt.org/z/MjcvochqP
// Dateiname: meine-makros.hpp
#ifndef MEINE_MAKROS_HPP // Include Guard
#define MEINE_MAKROS_HPP
#include <iostream> // cout, cerr
#include <vector>
#ifdef AUSGABE_AUF_STANDARD
# define OUT std::cout
#else
# define OUT std::cerr
#endif
#define MESSAGE(text) { (OUT) << text << "\n"; }
using container_type = std::vector<int>;
static constexpr unsigned SIZE = 10;
#endif
Godbolt Listing lst-0551-godb.cpp, https://godbolt.org/z/MjcvochqP:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/MjcvochqP
// Dateiname: meine-makros.hpp
#ifndef MEINE_MAKROS_HPP // Include Guard
#define MEINE_MAKROS_HPP
#include <iostream> // cout, cerr
#include <vector>
#ifdef AUSGABE_AUF_STANDARD
# define OUT std::cout
#else
# define OUT std::cerr
#endif
#define MESSAGE(text) { (OUT) << text << "\n"; }
using container_type = std::vector<int>;
static constexpr unsigned SIZE = 10;
#endif
Listing 21.2: Ihre Hauptdatei mit »main« bindet per »#include« die Headerdatei ein.
Book listing lst-0552-book.cpp:
// https://godbolt.org/z/zG91TMEa8
// Dateiname: makros.cpp
#define AUSGABE_AUF_STANDARD // Umschalten von cerr und cout
#include "meine-makros.hpp"
#include "meine-makros.hpp" // Ups, aus Versehen doppelt.
int main() {
MESSAGE("Programmstart");
container_type data(SIZE);
MESSAGE("Der Container hat " << data.size() << " Elemente.");
MESSAGE("Programmende");
OUT << "Das ging ja noch mal gut.\n";
}
Godbolt Listing lst-0552-godb.cpp, https://godbolt.org/z/zG91TMEa8:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/zG91TMEa8
// Dateiname: makros.cpp
#define AUSGABE_AUF_STANDARD // Umschalten von cerr und cout
#include "meine-makros.hpp"
#include "meine-makros.hpp" // Ups, aus Versehen doppelt.
int main() {
MESSAGE("Programmstart");
container_type data(SIZE);
MESSAGE("Der Container hat " << data.size() << " Elemente.");
MESSAGE("Programmende");
OUT << "Das ging ja noch mal gut.\n";
}
Listing 21.3: Das Ergebnis des Präprozessordurchlaufs
Book listing lst-0557-book.cpp:
// https://godbolt.org/z/6coqbhfKM
// …hier Inhalt von <vector>…
// …hier Inhalt von <iostream>…
using container_type = std::vector<int>;
static constexpr unsigned SIZE = 10;
int main() {
{ (std::cout) << "Programmstart" << "\n"; }
container_type data(SIZE);
{ (std::cout) << "Der Container hat " << data.size() << " Elemente." << "\n";}
{ (std::cout) << "Programmende" << "\n"; }
{ std::cout << "Das ging ja noch mal gut.\n"; }
}
Godbolt Listing lst-0557-godb.cpp, https://godbolt.org/z/6coqbhfKM:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/6coqbhfKM
// …hier Inhalt von <vector>…
// …hier Inhalt von <iostream>…
using container_type = std::vector<int>;
static constexpr unsigned SIZE = 10;
int main() {
{ (std::cout) << "Programmstart" << "\n"; }
container_type data(SIZE);
{ (std::cout) << "Der Container hat " << data.size() << " Elemente." << "\n";}
{ (std::cout) << "Programmende" << "\n"; }
{ std::cout << "Das ging ja noch mal gut.\n"; }
}
Listing 21.5: Die rein textuelle Ersetzung führt bei Makros zur Mehrfachausführung.
Book listing lst-0565-book.cpp:
// https://godbolt.org/z/jzKfabPh3
#include <cmath> // sin, cos
constexpr double max2(double a, double b) { return a > b ? a : b; }
#define MAX2(a,b) ((a) > (b) ? (a) : (b))
int main() {
double f = max2(sin(3.141592/2), cos(3.141592/2));
double e = MAX2(sin(3.141592/2), cos(3.141592/2));
}
Godbolt Listing lst-0565-godb.cpp, https://godbolt.org/z/jzKfabPh3:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/jzKfabPh3
#include <cmath> // sin, cos
constexpr double max2(double a, double b) { return a > b ? a : b; }
#define MAX2(a,b) ((a) > (b) ? (a) : (b))
int main() {
double f = max2(sin(3.141592/2), cos(3.141592/2));
double e = MAX2(sin(3.141592/2), cos(3.141592/2));
}
GodboltId:YzYz3x1zx
Book listing lst-0567-book.cpp:
// https://godbolt.org/z/YzYz3x1zx
#include <iostream>
#define MAX2(a,b) ((a) > (b) ? (a) : (b))
int main() {
int x = 0;
int y = 0;
int z = MAX2( ++x, ++y ); // (ERR) expandiert Argumente mehrfach
std::cout << "x:"<< x << " y:"<< y << " z:"<<z << '\n';
}
Godbolt Listing lst-0567-godb.cpp, https://godbolt.org/z/YzYz3x1zx:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/YzYz3x1zx
#include <iostream>
#define MAX2(a,b) ((a) > (b) ? (a) : (b))
int main() {
int x = 0;
int y = 0;
int z = MAX2( ++x, ++y ); // (ERR) expandiert Argumente mehrfach
std::cout << "x:"<< x << " y:"<< y << " z:"<<z << '\n';
}
GodboltId:5zrfvovaW
Book listing lst-0568-book.cpp:
// https://godbolt.org/z/5zrfvovaW
#include <string>
#include <cmath> // sin, cos
#define MAX2(a,b) ((a) > (b) ? (a) : (b))
int main() {
double e = MAX2(sin(3.141592/2), cos(3.141592/2));
int i = MAX2(10+12+45, 100/5+20);
std::string s = MAX2(std::string("Ernie"), std::string("Bert"));
}
Godbolt Listing lst-0568-godb.cpp, https://godbolt.org/z/5zrfvovaW:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/5zrfvovaW
#include <string>
#include <cmath> // sin, cos
#define MAX2(a,b) ((a) > (b) ? (a) : (b))
int main() {
double e = MAX2(sin(3.141592/2), cos(3.141592/2));
int i = MAX2(10+12+45, 100/5+20);
std::string s = MAX2(std::string("Ernie"), std::string("Bert"));
}
GodboltId:6xzTx83zE
Book listing lst-0569-book.cpp:
// https://godbolt.org/z/6xzTx83zE
#include <string>
#include <cmath> // sin, cos
constexpr double max2(double a, double b) { return a > b ? a : b; }
constexpr int max2(int a, int b) { return a > b ? a : b; }
std::string max2(const std::string &a, const std::string &b)
{ return a > b ? a : b; }
int main() {
double e = max2(sin(3.141592/2), cos(3.141592/2));
double i = max2(10+12+45, 100/5+20);
std::string s = max2("Ernie", "Bert");
}
Godbolt Listing lst-0569-godb.cpp, https://godbolt.org/z/6xzTx83zE:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/6xzTx83zE
#include <string>
#include <cmath> // sin, cos
constexpr double max2(double a, double b) { return a > b ? a : b; }
constexpr int max2(int a, int b) { return a > b ? a : b; }
std::string max2(const std::string &a, const std::string &b)
{ return a > b ? a : b; }
int main() {
double e = max2(sin(3.141592/2), cos(3.141592/2));
double i = max2(10+12+45, 100/5+20);
std::string s = max2("Ernie", "Bert");
}
Listing 21.6: Ein einfaches Funktionstemplate ist viel besser als ein Makro.
Book listing lst-0570-book.cpp:
// https://godbolt.org/z/acMjvxcM5
#include <string>
#include <cmath> // sin, cos
template<typename TYP>
constexpr TYP max2(const TYP &a, const TYP &b)
{ return a > b ? a : b; }
int main() {
double e = max2(sin(3.141592/2), cos(3.141592/2));
double i = max2(10+12+45, 100/5+20);
std::string s = max2(std::string("Ernie"), std::string("Bert"));
}
Godbolt Listing lst-0570-godb.cpp, https://godbolt.org/z/acMjvxcM5:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/acMjvxcM5
#include <string>
#include <cmath> // sin, cos
template<typename TYP>
constexpr TYP max2(const TYP &a, const TYP &b)
{ return a > b ? a : b; }
int main() {
double e = max2(sin(3.141592/2), cos(3.141592/2));
double i = max2(10+12+45, 100/5+20);
std::string s = max2(std::string("Ernie"), std::string("Bert"));
}
Listing 22.1: Das Programm »gzpack.cpp« nutzt eine C-Bibliothek. Hier sehen Sie die Sektion mit den Includes.
Book listing lst-0577-book.cpp:
// https://godbolt.org/z/9Trh8h8Mb
#include <string>
#include <vector>
#include <span> // C++20
#include <fstream> // ifstream
#include <stdexcept> // runtime_error
#include <iostream> // cerr
// C-Header:
#include <zlib.h> // gzXyz; sudo aptitude install libz-dev
#include <cerrno> // errno
#include <cstring> // strerror
namespace {
using std::string; using std::span; using std::byte;
Godbolt Listing lst-0577-godb.cpp, https://godbolt.org/z/9Trh8h8Mb:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/9Trh8h8Mb
#include <string>
#include <vector>
#include <span> // C++20
#include <fstream> // ifstream
#include <stdexcept> // runtime_error
#include <iostream> // cerr
// C-Header:
#include <zlib.h> // gzXyz; sudo aptitude install libz-dev
#include <cerrno> // errno
#include <cstring> // strerror
namespace {
using std::string; using std::span; using std::byte;
Listing 22.2: Dieser Teil von »gzpack.cpp« enthält alle verwendeten C-Funktionen.
Book listing lst-0578-book.cpp:
// https://godbolt.org/z/Yh7j1WEGc
class GzWriteStream { // RAII-Wrapper
public:
gzFile gz_ ; // C-Struct aus zlib.h
explicit GzWriteStream(const string& filename)
: gz_{gzopen(filename.c_str(),"wb9")} // 'w': write, 'b':binary, '9':level
{
if(gz_==NULL) throw std::runtime_error(std::strerror(errno));
}
~GzWriteStream() {
gzclose(gz_);
}
GzWriteStream& operator<<(span<char> &data) {
write(data);
return *this;
}
private:
void write(span<char> data) {
auto bytes = std::as_bytes(data); // C++20
auto res = gzwrite(gz_, bytes.data(), size(bytes));
if(res==0) throw std::runtime_error("Fehler beim Schreiben");
}
GzWriteStream(const GzWriteStream&) = delete; // keine Kopie
GzWriteStream& operator=(const GzWriteStream&) = delete; // keine Zuweisung
};
Godbolt Listing lst-0578-godb.cpp, https://godbolt.org/z/Yh7j1WEGc:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Yh7j1WEGc
class GzWriteStream { // RAII-Wrapper
public:
gzFile gz_ ; // C-Struct aus zlib.h
explicit GzWriteStream(const string& filename)
: gz_{gzopen(filename.c_str(),"wb9")} // 'w': write, 'b':binary, '9':level
{
if(gz_==NULL) throw std::runtime_error(std::strerror(errno));
}
~GzWriteStream() {
gzclose(gz_);
}
GzWriteStream& operator<<(span<char> &data) {
write(data);
return *this;
}
private:
void write(span<char> data) {
auto bytes = std::as_bytes(data); // C++20
auto res = gzwrite(gz_, bytes.data(), size(bytes));
if(res==0) throw std::runtime_error("Fehler beim Schreiben");
}
GzWriteStream(const GzWriteStream&) = delete; // keine Kopie
GzWriteStream& operator=(const GzWriteStream&) = delete; // keine Zuweisung
};
Listing 22.3: Dieser Teil von »gzpack.cpp« behandelt das Lesen und Schreiben der Dateien.
Book listing lst-0580-book.cpp:
// https://godbolt.org/z/3P9ToPEYq
std::vector<char> leseDatei(const string& fName) {
std::ifstream file{ fName, std::ifstream::binary };
if(!file) throw std::runtime_error("Fehler beim Oeffnen der Eingabe");
file.seekg(0, file.end); // ans Dateiende springen
const auto laenge = file.tellg(); // aktuelle Position ist Dateigröße
if(laenge > 1024*1024*1024)
throw std::runtime_error("Nicht mehr als 1 GB bitte");
file.seekg(0, file.beg); // zurück an den Anfang
std::vector<char> data(laenge); // Platz schaffen
file.read(data.data(), laenge); // in einem Rutsch lesen
return data; // wird nicht kopiert (Stichwort: RVO)
}
void packe(const string& fNameIn, const string& fNameOut) {
auto data = leseDatei(fNameIn); // lese Eingabe
GzWriteStream gz{fNameOut}; // initialisiere Ausgabe
gz << data;
}
Godbolt Listing lst-0580-godb.cpp, https://godbolt.org/z/3P9ToPEYq:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/3P9ToPEYq
std::vector<char> leseDatei(const string& fName) {
std::ifstream file{ fName, std::ifstream::binary };
if(!file) throw std::runtime_error("Fehler beim Oeffnen der Eingabe");
file.seekg(0, file.end); // ans Dateiende springen
const auto laenge = file.tellg(); // aktuelle Position ist Dateigröße
if(laenge > 1024*1024*1024)
throw std::runtime_error("Nicht mehr als 1 GB bitte");
file.seekg(0, file.beg); // zurück an den Anfang
std::vector<char> data(laenge); // Platz schaffen
file.read(data.data(), laenge); // in einem Rutsch lesen
return data; // wird nicht kopiert (Stichwort: RVO)
}
void packe(const string& fNameIn, const string& fNameOut) {
auto data = leseDatei(fNameIn); // lese Eingabe
GzWriteStream gz{fNameOut}; // initialisiere Ausgabe
gz << data;
}
Listing 22.4: Mit »main« des Programms »gzpack.cpp« ist das Beispiel komplett.
Book listing lst-0581-book.cpp:
// https://godbolt.org/z/4sod8vrr6
} // namespace
int main(int argc, const char* argv[]) {
try {
const std::vector<string> fNamen {argv+1, argv+argc};
for(auto fName : fNamen) {
std::cout << "packe " << fName << "... ";
packe(fName, fName+".gz");
std::cout << fName << ".gz"<< "\n";
}
} catch(std::runtime_error &exc) {
std::cerr << "Fehler: " << exc.what() << "\n";
}
}
Godbolt Listing lst-0581-godb.cpp, https://godbolt.org/z/4sod8vrr6:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/4sod8vrr6
} // namespace
int main(int argc, const char* argv[]) {
try {
const std::vector<string> fNamen {argv+1, argv+argc};
for(auto fName : fNamen) {
std::cout << "packe " << fName << "... ";
packe(fName, fName+".gz");
std::cout << fName << ".gz"<< "\n";
}
} catch(std::runtime_error &exc) {
std::cerr << "Fehler: " << exc.what() << "\n";
}
}
Listing 23.1: Der Aufruf eines Funktionstemplates klappt, solange der Funktionskörper mit den Templateparametern gültig ist.
Book listing lst-0591-book.cpp:
// https://godbolt.org/z/aMPj3K7EE
#include <iostream>
struct Zahl {
int wert_;
};
template<typename TYP>
void print(TYP value) {
std::cout << value << "\n";
}
int main() {
print(5);
print(-10.25);
print("Flamingo");
Zahl sieben { 7 };
print(sieben); // (ERR) cout << sieben gibt es nicht
}
Godbolt Listing lst-0591-godb.cpp, https://godbolt.org/z/aMPj3K7EE:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/aMPj3K7EE
#include <iostream>
struct Zahl {
int wert_;
};
template<typename TYP>
void print(TYP value) {
std::cout << value << "\n";
}
int main() {
print(5);
print(-10.25);
print("Flamingo");
Zahl sieben { 7 };
print(sieben); // (ERR) cout << sieben gibt es nicht
}
Listing 23.2: Mit und ohne explizite Typangabe beim Aufruf
Book listing lst-0594-book.cpp:
// https://godbolt.org/z/816Ys17aT
#include <iostream>
using std::cout;
template<typename TYP>
void func(TYP a) { cout << a <<" TYP\n"; }
void func(int a) { cout << a << " int\n"; }
int main() {
func<int>(8); // Ausgabe: 8 TYP
func(8); // Ausgabe: 8 int
}
Godbolt Listing lst-0594-godb.cpp, https://godbolt.org/z/816Ys17aT:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/816Ys17aT
#include <iostream>
using std::cout;
template<typename TYP>
void func(TYP a) { cout << a <<" TYP\n"; }
void func(int a) { cout << a << " int\n"; }
int main() {
func<int>(8); // Ausgabe: 8 TYP
func(8); // Ausgabe: 8 int
}
Listing 23.3: Ein Templateparameter kann auch eine konstante Zahl sein.
Book listing lst-0596-book.cpp:
// https://godbolt.org/z/c9xzM7EhP
#include <array>
#include <iostream> // cout
using std::array; using std::cout;
template<size_t SIZE>
array<int,SIZE> createArray() {
array<int,SIZE> result{};
return result;
}
int main() {
auto data = createArray<5>();
data[3] = 33;
for(auto e : data) cout << e << " ";
cout << "\n";
}
Godbolt Listing lst-0596-godb.cpp, https://godbolt.org/z/c9xzM7EhP:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/c9xzM7EhP
#include <array>
#include <iostream> // cout
using std::array; using std::cout;
template<size_t SIZE>
array<int,SIZE> createArray() {
array<int,SIZE> result{};
return result;
}
int main() {
auto data = createArray<5>();
data[3] = 33;
for(auto e : data) cout << e << " ";
cout << "\n";
}
Listing 23.4: Mit auto als Templateparameter können Sie jeden einfachen Wert angeben.
Book listing lst-0598-book.cpp:
template <auto value> void f() { }
f<10>(); // value bekommt Typ int
f<'a'>(); // value bekommt Typ char
Listing 23.5: Mit »auto« und … können Sie beliebige Werte als Templateparameter angeben.
Book listing lst-0599-book.cpp:
template<auto ... vs> struct GemischteListe {};
using Drei = GemischteListe<'a', 100, 'b'>;
Drei drei{};
Listing 23.6: Für »TYP« wird vom Compiler »const&« ermittelt.
Book listing lst-0601-book.cpp:
// https://godbolt.org/z/cYsTo371z
#include <iostream>
const int& a_oder_b(int auswahl) {
static const int a = 42;
static const int b = 73;
if(auswahl==1)
return a; // const& auf innere Variable a zurückgeben
else
return b; // const& auf innere Variable b zurückgeben
}
template<typename TYP>
TYP add(TYP a, TYP b) {
return a + b;
}
int main() {
auto res = add(
a_oder_b(0), // const int&
a_oder_b(1) ); // const int&
std::cout << res << "\n"; // Ausgabe: 115
}
Godbolt Listing lst-0601-godb.cpp, https://godbolt.org/z/cYsTo371z:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/cYsTo371z
#include <iostream>
const int& a_oder_b(int auswahl) {
static const int a = 42;
static const int b = 73;
if(auswahl==1)
return a; // const& auf innere Variable a zurückgeben
else
return b; // const& auf innere Variable b zurückgeben
}
template<typename TYP>
TYP add(TYP a, TYP b) {
return a + b;
}
int main() {
auto res = add(
a_oder_b(0), // const int&
a_oder_b(1) ); // const int&
std::cout << res << "\n"; // Ausgabe: 115
}
Listing 23.7: Auch eine Methode kann ein Template sein.
Book listing lst-0603-book.cpp:
// https://godbolt.org/z/bfofn76Ke
#include <iostream>
class Printer {
std::ostream& trg_;
public:
explicit Printer(std::ostream& target)
: trg_(target)
{}
template<typename TYP>
Printer& print(const TYP& arg) {
trg_ << arg;
return *this;
}
};
int main() {
Printer normal(std::cout);
normal.print(7).print(" ").print(3.1415).print("\n");
Printer fehler(std::cerr);
fehler.print(8).print(" ").print(2.7183).print("\n");
}
Godbolt Listing lst-0603-godb.cpp, https://godbolt.org/z/bfofn76Ke:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/bfofn76Ke
#include <iostream>
class Printer {
std::ostream& trg_;
public:
explicit Printer(std::ostream& target)
: trg_(target)
{}
template<typename TYP>
Printer& print(const TYP& arg) {
trg_ << arg;
return *this;
}
};
int main() {
Printer normal(std::cout);
normal.print(7).print(" ").print(3.1415).print("\n");
Printer fehler(std::cerr);
fehler.print(8).print(" ").print(2.7183).print("\n");
}
Listing 23.8: Auch in der Standardbibliothek finden Sie allerlei Funktionstemplates.
Book listing lst-0604-book.cpp:
// https://godbolt.org/z/oTn1K4sGG
#include <vector>
#include <iostream> // cout, ostream
#include <algorithm> // sort, copy
#include <iterator> // ostream_iterator
int main() {
std::ostream_iterator<int> oit(std::cout," ");
std::vector data { 100, 50, 1, 75, 25, 0 }; // vector<int>
std::sort(std::begin(data), std::end(data)); // Iteratorenpaar
std::copy(std::begin(data), std::end(data), oit); // Iteratorenpaar
std::cout << '\n'; // Ausgabe: 0 1 25 50 75 100
std::ranges::reverse(data); // Range
std::ranges::copy(data, oit); // Range
std::cout << '\n'; // Ausgabe: 100 75 50 25 1 0
}
Godbolt Listing lst-0604-godb.cpp, https://godbolt.org/z/oTn1K4sGG:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/oTn1K4sGG
#include <vector>
#include <iostream> // cout, ostream
#include <algorithm> // sort, copy
#include <iterator> // ostream_iterator
int main() {
std::ostream_iterator<int> oit(std::cout," ");
std::vector data { 100, 50, 1, 75, 25, 0 }; // vector<int>
std::sort(std::begin(data), std::end(data)); // Iteratorenpaar
std::copy(std::begin(data), std::end(data), oit); // Iteratorenpaar
std::cout << '\n'; // Ausgabe: 0 1 25 50 75 100
std::ranges::reverse(data); // Range
std::ranges::copy(data, oit); // Range
std::cout << '\n'; // Ausgabe: 100 75 50 25 1 0
}
Listing 23.9: Eigenen Algorithmen übergeben Sie Ranges als Argumente, nicht den Container.
Book listing lst-0605-book.cpp:
// https://godbolt.org/z/h3baE65od
#include <iostream>
#include <vector>
#include <set>
#include <bitset>
#include <ranges>
namespace rng = std::ranges;
std::ostream& druckeBinaer(std::ostream& os, rng::input_range auto&& range) {
for(auto&& elem : range) {
std::bitset<4> x(elem); // Zahl in bitset kopieren
os << x << " ";
}
return os;
}
int main()
{
std::vector vdata { 2, 0, 15, 12 };
druckeBinaer(std::cout, vdata) << "\n";
// Ausgabe: 0010 0000 1111 1100
std::set sdata { 2, 0, 12, 15 };
druckeBinaer(std::cout, sdata) << "\n";
// Ausgabe: 0000 0010 1100 1111
int adata[] = { 0,1,2,13,14,15 };
druckeBinaer(std::cout, adata) << "\n";
// Ausgabe: 0000 0001 0010 1101 1110 1111
}
Godbolt Listing lst-0605-godb.cpp, https://godbolt.org/z/h3baE65od:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/h3baE65od
#include <iostream>
#include <vector>
#include <set>
#include <bitset>
#include <ranges>
namespace rng = std::ranges;
std::ostream& druckeBinaer(std::ostream& os, rng::input_range auto&& range) {
for(auto&& elem : range) {
std::bitset<4> x(elem); // Zahl in bitset kopieren
os << x << " ";
}
return os;
}
int main()
{
std::vector vdata { 2, 0, 15, 12 };
druckeBinaer(std::cout, vdata) << "\n";
// Ausgabe: 0010 0000 1111 1100
std::set sdata { 2, 0, 12, 15 };
druckeBinaer(std::cout, sdata) << "\n";
// Ausgabe: 0000 0010 1100 1111
int adata[] = { 0,1,2,13,14,15 };
druckeBinaer(std::cout, adata) << "\n";
// Ausgabe: 0000 0001 0010 1101 1110 1111
}
Listing 23.10: Eigenen Algorithmen übergeben Sie Iteratoren als Argumente, nicht den Container.
Book listing lst-0606-book.cpp:
// https://godbolt.org/z/13eMxKTfj
#include <iostream>
#include <vector>
#include <set>
#include <bitset>
template<typename IT>
std::ostream& druckeBinaer(std::ostream& os, IT begin, IT end)
{
for(IT it=begin; it != end; ++it) {
std::bitset<4> x(*it); // Zahl in bitset kopieren
os << x << " ";
}
return os;
}
int main()
{
std::vector<int> vdata { 2, 0, 15, 12 };
druckeBinaer(std::cout, vdata.cbegin(), vdata.cend()) << "\n";
// Ausgabe: 0010 0000 1111 1100
std::set<int> sdata { 2, 0, 12, 15 };
druckeBinaer(std::cout, std::begin(sdata), std::end(sdata)) << "\n";
// Ausgabe: 0000 0010 1100 1111
int adata[] = { 0,1,2,13,14,15 };
druckeBinaer(std::cout, std::begin(adata), std::end(adata)) << "\n";
// Ausgabe: 0000 0001 0010 1101 1110 1111
}
Godbolt Listing lst-0606-godb.cpp, https://godbolt.org/z/13eMxKTfj:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/13eMxKTfj
#include <iostream>
#include <vector>
#include <set>
#include <bitset>
template<typename IT>
std::ostream& druckeBinaer(std::ostream& os, IT begin, IT end)
{
for(IT it=begin; it != end; ++it) {
std::bitset<4> x(*it); // Zahl in bitset kopieren
os << x << " ";
}
return os;
}
int main()
{
std::vector<int> vdata { 2, 0, 15, 12 };
druckeBinaer(std::cout, vdata.cbegin(), vdata.cend()) << "\n";
// Ausgabe: 0010 0000 1111 1100
std::set<int> sdata { 2, 0, 12, 15 };
druckeBinaer(std::cout, std::begin(sdata), std::end(sdata)) << "\n";
// Ausgabe: 0000 0010 1100 1111
int adata[] = { 0,1,2,13,14,15 };
druckeBinaer(std::cout, std::begin(adata), std::end(adata)) << "\n";
// Ausgabe: 0000 0001 0010 1101 1110 1111
}
Listing 23.11: So finden Sie den Zahlenbereich der Ganzzahltypen heraus.
Book listing lst-0608-book.cpp:
// https://godbolt.org/z/oY9v9a8d6
#include <iostream> // cout
#include <limits> // numeric_limits
template<typename INT_TYP> // Template mit Typargument
void infos(const char* name) {
using L = typename std::numeric_limits<INT_TYP>; // kürzer umbenennen
std::cout
<< name
<< " zahlenbits:" << L::digits // Bits ohne Vorzeichenbit
<< " vorzeichen:" << L::is_signed // speichert Vorzeichen?
<< " min:"<< (long long)L::min() // kleinster möglicher Wert
<< " max:"<< (long long)L::max() // größter möglicher Wert
<< "\n";
}
int main() {
infos<signed char>("char"); // kleinster int-Typ
infos<short>("short");
infos<int>("int");
infos<long>("long");
infos<long long>("long long"); // größter int-Typ
}
Godbolt Listing lst-0608-godb.cpp, https://godbolt.org/z/oY9v9a8d6:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/oY9v9a8d6
#include <iostream> // cout
#include <limits> // numeric_limits
template<typename INT_TYP> // Template mit Typargument
void infos(const char* name) {
using L = typename std::numeric_limits<INT_TYP>; // kürzer umbenennen
std::cout
<< name
<< " zahlenbits:" << L::digits // Bits ohne Vorzeichenbit
<< " vorzeichen:" << L::is_signed // speichert Vorzeichen?
<< " min:"<< (long long)L::min() // kleinster möglicher Wert
<< " max:"<< (long long)L::max() // größter möglicher Wert
<< "\n";
}
int main() {
infos<signed char>("char"); // kleinster int-Typ
infos<short>("short");
infos<int>("int");
infos<long>("long");
infos<long long>("long long"); // größter int-Typ
}
Listing 23.12: Eine Funktion als Parameter
Book listing lst-0609-book.cpp:
#include <functional> // function
int berechne(int a, int b, std::function<int(int,int)> binop) {
return binop(a,b);
}
Listing 23.13: Verwenden Sie den Namen einer passenden Funktion als Funktionsparameter.
Book listing lst-0612-book.cpp:
// https://godbolt.org/z/7YKjcTbhn
#include <functional> // function
#include <iostream> // cout
int berechne(int a, int b, std::function<int(int,int)> binop) {
return binop(a,b);
}
int plus(int a, int b) { return a+b; }
int mal(int a, int b) { return a*b; }
int main() {
std::cout << berechne(3, 4, plus) << "\n"; // Ausgabe: 7
std::cout << berechne(3, 4, mal) << "\n"; // Ausgabe: 12
}
Godbolt Listing lst-0612-godb.cpp, https://godbolt.org/z/7YKjcTbhn:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/7YKjcTbhn
#include <functional> // function
#include <iostream> // cout
int berechne(int a, int b, std::function<int(int,int)> binop) {
return binop(a,b);
}
int plus(int a, int b) { return a+b; }
int mal(int a, int b) { return a*b; }
int main() {
std::cout << berechne(3, 4, plus) << "\n"; // Ausgabe: 7
std::cout << berechne(3, 4, mal) << "\n"; // Ausgabe: 12
}
Listing 23.14: Es ist egal, ob Sie beim Aufruf den Adressoperator verwenden oder nicht.
Book listing lst-0615-book.cpp:
// https://godbolt.org/z/WbnThTs8e
#include <functional> // function
#include <iostream> // cout
int berechne(int a, int b, std::function<int(int,int)> binop) {
return binop(a,b);
}
int plus(int a, int b) { return a+b; }
int mal(int a, int b) { return a*b; }
int main() {
std::cout << berechne(3, 4, plus) << "\n"; // Wert-Schreibweise
std::cout << berechne(3, 4, mal) << "\n"; // Wert-Schreibweise
std::cout << berechne(3, 4, &plus) << "\n"; // Zeiger-Schreibweise
std::cout << berechne(3, 4, &mal) << "\n"; // Zeiger-Schreibweise
}
Godbolt Listing lst-0615-godb.cpp, https://godbolt.org/z/WbnThTs8e:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/WbnThTs8e
#include <functional> // function
#include <iostream> // cout
int berechne(int a, int b, std::function<int(int,int)> binop) {
return binop(a,b);
}
int plus(int a, int b) { return a+b; }
int mal(int a, int b) { return a*b; }
int main() {
std::cout << berechne(3, 4, plus) << "\n"; // Wert-Schreibweise
std::cout << berechne(3, 4, mal) << "\n"; // Wert-Schreibweise
std::cout << berechne(3, 4, &plus) << "\n"; // Zeiger-Schreibweise
std::cout << berechne(3, 4, &mal) << "\n"; // Zeiger-Schreibweise
}
Listing 23.15: Eine Klasse mit »operator()« erzeugt Funktionsobjekte.
Book listing lst-0616-book.cpp:
// https://godbolt.org/z/Px83WPKfq
#include <iostream> // cout
using std::cout;
class Inkrement {
int menge_;
public:
explicit Inkrement(int menge) : menge_{menge} {}
int operator()(int wert) const { // macht Instanzen aufrufbar
return wert + menge_;
}
void clear() {
menge_ = 0;
}
};
int main() {
Inkrement plusVier{4}; // Instanz erzeugen
Inkrement plusElf{11}; // noch eine Instanz
cout << plusVier(8) << "\n"; // Ausgabe: 12
int erg = 2 * plusElf(5) - 7; // erg ist 25
cout << plusElf(erg/5) << "\n"; // Ausgabe: 16
cout << 3 * Inkrement{1}(7) << "\n"; // Ausgabe: 24
Inkrement plusNix = plusElf;
plusNix.clear(); // Zustand ändern
cout << plusNix(1) << "\n"; // Ausgabe: 1
}
Godbolt Listing lst-0616-godb.cpp, https://godbolt.org/z/Px83WPKfq:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Px83WPKfq
#include <iostream> // cout
using std::cout;
class Inkrement {
int menge_;
public:
explicit Inkrement(int menge) : menge_{menge} {}
int operator()(int wert) const { // macht Instanzen aufrufbar
return wert + menge_;
}
void clear() {
menge_ = 0;
}
};
int main() {
Inkrement plusVier{4}; // Instanz erzeugen
Inkrement plusElf{11}; // noch eine Instanz
cout << plusVier(8) << "\n"; // Ausgabe: 12
int erg = 2 * plusElf(5) - 7; // erg ist 25
cout << plusElf(erg/5) << "\n"; // Ausgabe: 16
cout << 3 * Inkrement{1}(7) << "\n"; // Ausgabe: 24
Inkrement plusNix = plusElf;
plusNix.clear(); // Zustand ändern
cout << plusNix(1) << "\n"; // Ausgabe: 1
}
Listing 23.16: Eine Klasse mit einer normalen Methode
Book listing lst-0619-book.cpp:
// https://godbolt.org/z/EExfde3vP
#include <iostream> // cout
using std::cout;
class Hinzu {
int menge_;
public:
explicit Hinzu(int menge) : menge_{menge} {}
int hinzu(int wert) const { // statt operator()
return wert + menge_;
}
void clear() {
menge_ = 0;
}
};
int main() {
Hinzu plusVier{4}; // Instanz erzeugen
Hinzu plusElf{11}; // noch eine Instanz
cout << plusVier.hinzu(8) << "\n"; // Ausgabe: 12
int erg = 2 * plusElf.hinzu(5) - 7; // erg ist 25
cout << plusElf.hinzu(erg/5) << "\n"; // Ausgabe: 16
cout << 3 * Hinzu{1}.hinzu(7) << "\n"; // Ausgabe: 24
Hinzu plusNix = plusElf;
plusNix.clear(); // Zustand ändern
cout << plusNix.hinzu(1) << "\n"; // Ausgabe: 1
}
Godbolt Listing lst-0619-godb.cpp, https://godbolt.org/z/EExfde3vP:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/EExfde3vP
#include <iostream> // cout
using std::cout;
class Hinzu {
int menge_;
public:
explicit Hinzu(int menge) : menge_{menge} {}
int hinzu(int wert) const { // statt operator()
return wert + menge_;
}
void clear() {
menge_ = 0;
}
};
int main() {
Hinzu plusVier{4}; // Instanz erzeugen
Hinzu plusElf{11}; // noch eine Instanz
cout << plusVier.hinzu(8) << "\n"; // Ausgabe: 12
int erg = 2 * plusElf.hinzu(5) - 7; // erg ist 25
cout << plusElf.hinzu(erg/5) << "\n"; // Ausgabe: 16
cout << 3 * Hinzu{1}.hinzu(7) << "\n"; // Ausgabe: 24
Hinzu plusNix = plusElf;
plusNix.clear(); // Zustand ändern
cout << plusNix.hinzu(1) << "\n"; // Ausgabe: 1
}
Listing 23.17: Mit »operator<« als Funktion können Sie nur eine Sortierung implementieren.
Book listing lst-0620-book.cpp:
// https://godbolt.org/z/3ch51ov87
#include <set>
#include <string>
#include <iostream> // cout
using std::string; using std::set; using std::cout;
struct Zwerg {
string name_;
unsigned jahr_;
};
bool operator<(const Zwerg& a, const Zwerg& b) {
return a.name_ < b.name_;
}
int main() {
set zwerge{ Zwerg{"Balin", 2763}, Zwerg{"Dwalin", 2772},
Zwerg{"Oin", 2774}, Zwerg{"Gloin", 2783}, Zwerg{"Thorin", 2746},
Zwerg{"Fili", 2859}, Zwerg{"Kili", 2864} };
for(const auto& z : zwerge) // sortierte Ausgabe: "Balin" bis "Thorin"
cout << z.name_ << " ";
cout << "\n";
}
Godbolt Listing lst-0620-godb.cpp, https://godbolt.org/z/3ch51ov87:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/3ch51ov87
#include <set>
#include <string>
#include <iostream> // cout
using std::string; using std::set; using std::cout;
struct Zwerg {
string name_;
unsigned jahr_;
};
bool operator<(const Zwerg& a, const Zwerg& b) {
return a.name_ < b.name_;
}
int main() {
set zwerge{ Zwerg{"Balin", 2763}, Zwerg{"Dwalin", 2772},
Zwerg{"Oin", 2774}, Zwerg{"Gloin", 2783}, Zwerg{"Thorin", 2746},
Zwerg{"Fili", 2859}, Zwerg{"Kili", 2864} };
for(const auto& z : zwerge) // sortierte Ausgabe: "Balin" bis "Thorin"
cout << z.name_ << " ";
cout << "\n";
}
Listing 23.18: Ein Funktor ohne Schnickschnack, aber mit großem Nutzen
Book listing lst-0622-book.cpp:
struct NachJahr { // implementiert less-than nach Zwerg::jahr_
bool operator()(const Zwerg& a, const Zwerg& b) const {
return a.jahr_ < b.jahr_;
}
};
GodboltId:53EcTMo3e
Book listing lst-0623-book.cpp:
// https://godbolt.org/z/53EcTMo3e
set<Zwerg,NachJahr> zwerge2{begin(zwerge), end(zwerge)};
for(const auto& z : zwerge2) // anders sortierte Ausgabe
cout << z.jahr_ << " ";
Godbolt Listing lst-0623-godb.cpp, https://godbolt.org/z/53EcTMo3e:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/53EcTMo3e
set<Zwerg,NachJahr> zwerge2{begin(zwerge), end(zwerge)};
for(const auto& z : zwerge2) // anders sortierte Ausgabe
cout << z.jahr_ << " ";
Listing 23.19: Viele Algorithmen der Standardbibliothek arbeiten ebenfalls mit »operator<«.
Book listing lst-0627-book.cpp:
// https://godbolt.org/z/MrcGhxTdT
#include <vector>
#include <algorithm> // sort
// Definitionen und weitere Includes wie zuvor
int main() {
vector zwerge{ // initialisieren wie zuvor
/* sortieren */
std::sort(begin(zwerge), end(zwerge));
// ausgeben wie zuvor …
Godbolt Listing lst-0627-godb.cpp, https://godbolt.org/z/MrcGhxTdT:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/MrcGhxTdT
#include <vector>
#include <algorithm> // sort
// Definitionen und weitere Includes wie zuvor
int main() {
vector zwerge{ // initialisieren wie zuvor
/* sortieren */
std::sort(begin(zwerge), end(zwerge));
// ausgeben wie zuvor …
Listing 23.20: Mit der Zugriffsklausel können Sie im Lambda auf äußere Variablen zugreifen.
Book listing lst-0634-book.cpp:
// https://godbolt.org/z/ers9eWPbG
#include <vector>
#include <string>
#include <algorithm> // sort
#include <iostream> // cout
using std::string; using std::vector; using std::cout;
// wie zuvor
int main() {
vector zwerge{ // wie zuvor
/* sortieren */
bool rueckwaerts = true; // oder false. Variable außerhalb des Lambdas
std::ranges::sort(zwerge,
[rueckwaerts](const Zwerg& a, const Zwerg& b) {
if(rueckwaerts)
return a.name_ > b.name_;
else
return a.name_ < b.name_;
}
);
/* ausgeben */
for(const auto& z : zwerge) // rückwärts: "Thorin" bis "Balin"
cout << z.name_ << " ";
cout << "\n";
}
Godbolt Listing lst-0634-godb.cpp, https://godbolt.org/z/ers9eWPbG:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/ers9eWPbG
#include <vector>
#include <string>
#include <algorithm> // sort
#include <iostream> // cout
using std::string; using std::vector; using std::cout;
// wie zuvor
int main() {
vector zwerge{ // wie zuvor
/* sortieren */
bool rueckwaerts = true; // oder false. Variable außerhalb des Lambdas
std::ranges::sort(zwerge,
[rueckwaerts](const Zwerg& a, const Zwerg& b) {
if(rueckwaerts)
return a.name_ > b.name_;
else
return a.name_ < b.name_;
}
);
/* ausgeben */
for(const auto& z : zwerge) // rückwärts: "Thorin" bis "Balin"
cout << z.name_ << " ";
cout << "\n";
}
Listing 23.21: Die Zugriffsklausel kann auch Referenzen enthalten.
Book listing lst-0635-book.cpp:
// https://godbolt.org/z/4zYsWW9Wq
#include <vector>
#include <string>
#include <algorithm> // sort
#include <iostream> // cout
using std::string; using std::vector; using std::cout;
// wie zuvor
int main() {
vector zwerge{ // wie zuvor
/* sortieren */
bool rueckwaerts = true; // oder false. Variable außerhalb des Lambdas
unsigned richtigrum = 0; // zählt < mit
unsigned falschrum = 0; // zählt > mit
std::ranges::sort(zwerge,
[rueckwaerts,&falschrum,&richtigrum](const Zwerg& a, const Zwerg& b) {
bool result = rueckwaerts
? a.name_ > b.name_
: a.name_ < b.name_;
if(result==false) ++falschrum; else ++richtigrum;
return result;
}
);
/* ausgeben */
cout << "Falschrum:" << falschrum << " Richtigrum: " << richtigrum << "\n";
for(const auto& z : zwerge) // rückwärts: "Thorin" bis "Balin"
cout << z.name_ << " ";
cout << "\n";
}
Godbolt Listing lst-0635-godb.cpp, https://godbolt.org/z/4zYsWW9Wq:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/4zYsWW9Wq
#include <vector>
#include <string>
#include <algorithm> // sort
#include <iostream> // cout
using std::string; using std::vector; using std::cout;
// wie zuvor
int main() {
vector zwerge{ // wie zuvor
/* sortieren */
bool rueckwaerts = true; // oder false. Variable außerhalb des Lambdas
unsigned richtigrum = 0; // zählt < mit
unsigned falschrum = 0; // zählt > mit
std::ranges::sort(zwerge,
[rueckwaerts,&falschrum,&richtigrum](const Zwerg& a, const Zwerg& b) {
bool result = rueckwaerts
? a.name_ > b.name_
: a.name_ < b.name_;
if(result==false) ++falschrum; else ++richtigrum;
return result;
}
);
/* ausgeben */
cout << "Falschrum:" << falschrum << " Richtigrum: " << richtigrum << "\n";
for(const auto& z : zwerge) // rückwärts: "Thorin" bis "Balin"
cout << z.name_ << " ";
cout << "\n";
}
Listing 23.22: »mutable« macht Wert-Captures in Lambdas veränderbar.
Book listing lst-0637-book.cpp:
// https://godbolt.org/z/zMWo69974
#include <iostream>
int main() {
int count = 0;
auto plus1 = [count](int x) mutable { // count als Kopie
std::cout << ++count; return x+1;
};
for(int i=0; i<5; ++i) {
plus1(i);
}
std::cout << "\n";
// Ausgabe: 12345
}
Godbolt Listing lst-0637-godb.cpp, https://godbolt.org/z/zMWo69974:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/zMWo69974
#include <iostream>
int main() {
int count = 0;
auto plus1 = [count](int x) mutable { // count als Kopie
std::cout << ++count; return x+1;
};
for(int i=0; i<5; ++i) {
plus1(i);
}
std::cout << "\n";
// Ausgabe: 12345
}
Listing 23.23: Wenn möglich, besser ohne mutable
Book listing lst-0638-book.cpp:
// https://godbolt.org/z/8GxPMEc5o
#include <iostream>
int main() {
int count = 0;
auto plus1 = [&count](int x) { // count als Referenz
++count; return x+1;
};
for(int i=0; i<5; ++i) { plus1(i); }
std::cout << "plus1 wurde " << count << " Mal aufgerufen\n";
// Ausgabe: plus1 wurde 5 Mal aufgerufen
}
Godbolt Listing lst-0638-godb.cpp, https://godbolt.org/z/8GxPMEc5o:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/8GxPMEc5o
#include <iostream>
int main() {
int count = 0;
auto plus1 = [&count](int x) { // count als Referenz
++count; return x+1;
};
for(int i=0; i<5; ++i) { plus1(i); }
std::cout << "plus1 wurde " << count << " Mal aufgerufen\n";
// Ausgabe: plus1 wurde 5 Mal aufgerufen
}
GodboltId:YWe15Ehd8
Book listing lst-0641-book.cpp:
// https://godbolt.org/z/YWe15Ehd8
#include <iostream>
#include <string>
using std::cout; using std::string; using namespace std::literals;
auto min2 = [](const auto &a, const auto &b) {
return a<b ? a : b;
};
auto min3 = [](const auto &a, const auto &b, const auto &c) {
return min2(a, min2(b,c));
};
int main() {
cout << min3( 3, 7, 2 ) << '\n'; // Ausgabe: 2
cout << min3( 8.11, 113.2, -3.1 ) << '\n'; // Ausgabe: –3.1
cout << min3( "Zoo"s, "Affe"s, "Muli"s ) << '\n'; // Ausgabe: Affe
}
Godbolt Listing lst-0641-godb.cpp, https://godbolt.org/z/YWe15Ehd8:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/YWe15Ehd8
#include <iostream>
#include <string>
using std::cout; using std::string; using namespace std::literals;
auto min2 = [](const auto &a, const auto &b) {
return a<b ? a : b;
};
auto min3 = [](const auto &a, const auto &b, const auto &c) {
return min2(a, min2(b,c));
};
int main() {
cout << min3( 3, 7, 2 ) << '\n'; // Ausgabe: 2
cout << min3( 8.11, 113.2, -3.1 ) << '\n'; // Ausgabe: –3.1
cout << min3( "Zoo"s, "Affe"s, "Muli"s ) << '\n'; // Ausgabe: Affe
}
GodboltId:nenW8aM81
Book listing lst-0642-book.cpp:
// https://godbolt.org/z/nenW8aM81
auto min2 = []<typename T>(const T &a, const T &b) {
return a<b ? a : b;
};
auto min3 = []<typename T>(const T &a, const T &b, const T &c) {
return min2(a, min2(b,c));
};
Godbolt Listing lst-0642-godb.cpp, https://godbolt.org/z/nenW8aM81:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/nenW8aM81
auto min2 = []<typename T>(const T &a, const T &b) {
return a<b ? a : b;
};
auto min3 = []<typename T>(const T &a, const T &b, const T &c) {
return min2(a, min2(b,c));
};
Listing 23.24: Concepts können auf unterschiedliche Weise geschrieben werden.
Book listing lst-0643-book.cpp:
// https://godbolt.org/z/W6cdra8K9
#include <concepts> // integral
#include <iostream>
using namespace std;
// Concept explizit mit requires
template<typename T> requires integral<T>
auto add_1(T val) { return val+1; }
// abgekürztes Concept
template<integral T>
auto add_2(T val) { return val+2; }
// abgekürztes Funktionstemplate mit Concept
auto add_3(integral auto val) { return val+3; }
// Ad-hoc-requires für Funktionstemplate
auto add_4(auto val) requires integral<decltype(val)>
{ return val+4; }
int main() {
cout << add_1(1) << '\n'; // Ausgabe: 2
cout << add_2(1) << '\n'; // Ausgabe: 3
cout << add_3(1) << '\n'; // Ausgabe: 4
cout << add_4(1) << '\n'; // Ausgabe: 5
cout << add_3("text") << '\n'; // (ERR) Fehler
integral auto val = add_1(99); // auch für auto-Variablen
cout << val << '\n'; // Ausgabe: 100
}
Godbolt Listing lst-0643-godb.cpp, https://godbolt.org/z/W6cdra8K9:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/W6cdra8K9
#include <concepts> // integral
#include <iostream>
using namespace std;
// Concept explizit mit requires
template<typename T> requires integral<T>
auto add_1(T val) { return val+1; }
// abgekürztes Concept
template<integral T>
auto add_2(T val) { return val+2; }
// abgekürztes Funktionstemplate mit Concept
auto add_3(integral auto val) { return val+3; }
// Ad-hoc-requires für Funktionstemplate
auto add_4(auto val) requires integral<decltype(val)>
{ return val+4; }
int main() {
cout << add_1(1) << '\n'; // Ausgabe: 2
cout << add_2(1) << '\n'; // Ausgabe: 3
cout << add_3(1) << '\n'; // Ausgabe: 4
cout << add_4(1) << '\n'; // Ausgabe: 5
cout << add_3("text") << '\n'; // (ERR) Fehler
integral auto val = add_1(99); // auch für auto-Variablen
cout << val << '\n'; // Ausgabe: 100
}
Listing 23.25: Mit Concepts können Sie einzelne Überladungen einschränken.
Book listing lst-0644-book.cpp:
// https://godbolt.org/z/Kxrz5ETh6
#include <concepts> // integral, floating_point
#include <iostream>
using namespace std;
int64_t trunc_to_10(integral auto val) { return (val/10)*10; }
int64_t trunc_to_10(floating_point auto val) { return int64_t(val/10)*10; }
int main() {
cout << trunc_to_10(144) << '\n'; // Ausgabe: 140
cout << trunc_to_10(122.2) << '\n'; // Ausgabe: 120
}
Godbolt Listing lst-0644-godb.cpp, https://godbolt.org/z/Kxrz5ETh6:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Kxrz5ETh6
#include <concepts> // integral, floating_point
#include <iostream>
using namespace std;
int64_t trunc_to_10(integral auto val) { return (val/10)*10; }
int64_t trunc_to_10(floating_point auto val) { return int64_t(val/10)*10; }
int main() {
cout << trunc_to_10(144) << '\n'; // Ausgabe: 140
cout << trunc_to_10(122.2) << '\n'; // Ausgabe: 120
}
GodboltId:eaGre4bqr
Book listing lst-0646-book.cpp:
// https://godbolt.org/z/eaGre4bqr
auto min2(const std::integral auto &a, const std::integral auto &b) {
return a<b ? a : b;
};
auto min3 = []<std::integral T>(const T &a, const T &b, const T &c) {
return min2(a, min2(b,c));
};
int main() {
cout << min3( 3, 7, 2 ) << '\n';
cout << min3( 8.11, 113.2, -3.1 ) << '\n'; // (ERR) Fehler: kein integraler Typ
Godbolt Listing lst-0646-godb.cpp, https://godbolt.org/z/eaGre4bqr:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/eaGre4bqr
auto min2(const std::integral auto &a, const std::integral auto &b) {
return a<b ? a : b;
};
auto min3 = []<std::integral T>(const T &a, const T &b, const T &c) {
return min2(a, min2(b,c));
};
int main() {
cout << min3( 3, 7, 2 ) << '\n';
cout << min3( 8.11, 113.2, -3.1 ) << '\n'; // (ERR) Fehler: kein integraler Typ
Listing 23.26: Geben Sie weitere Bedingungen mit requires an.
Book listing lst-0647-book.cpp:
// https://godbolt.org/z/orTK9daa3
#include <concepts>
#include <iostream>
#include <string>
using namespace std; using namespace std::literals;
string mk_string(integral auto val) { return to_string(val); }
string mk_string(string val) { return '['+val+']'; }
template<typename T>
requires copyable<T> && // Typanforderung
requires (T t) { mk_string(t) + mk_string(t); } && // einfache Anforderung
requires (T t) { // zusammengesetzte Anforderung
{mk_string(t)} -> same_as<string>; // gültiger Ausdruck muss Bedingung erfüllen
}
string dbl_quote(const T& val) {
T val2{val}; // Kopie erzeugen (nur zu Demozwecken)
return '"' + mk_string(val) + mk_string(val2) + '"';
}
int main() {
cout << dbl_quote(10) << '\n'; // Ausgabe: "1010"
cout << dbl_quote("ab"s) << '\n'; // Ausgabe: "[ab][ab]"
cout << dbl_quote(3.14) << '\n'; // (ERR) Fehler: keine passende mk_string-Überladung
}
Godbolt Listing lst-0647-godb.cpp, https://godbolt.org/z/orTK9daa3:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/orTK9daa3
#include <concepts>
#include <iostream>
#include <string>
using namespace std; using namespace std::literals;
string mk_string(integral auto val) { return to_string(val); }
string mk_string(string val) { return '['+val+']'; }
template<typename T>
requires copyable<T> && // Typanforderung
requires (T t) { mk_string(t) + mk_string(t); } && // einfache Anforderung
requires (T t) { // zusammengesetzte Anforderung
{mk_string(t)} -> same_as<string>; // gültiger Ausdruck muss Bedingung erfüllen
}
string dbl_quote(const T& val) {
T val2{val}; // Kopie erzeugen (nur zu Demozwecken)
return '"' + mk_string(val) + mk_string(val2) + '"';
}
int main() {
cout << dbl_quote(10) << '\n'; // Ausgabe: "1010"
cout << dbl_quote("ab"s) << '\n'; // Ausgabe: "[ab][ab]"
cout << dbl_quote(3.14) << '\n'; // (ERR) Fehler: keine passende mk_string-Überladung
}
Listing 23.27: Definieren Sie wiederkehrende Anforderungen mit concept.
Book listing lst-0648-book.cpp:
// https://godbolt.org/z/Tcxnr6jTM
template<typename T>
concept dbl_quotable = copyable<T> &&
requires (T t) { mk_string(t) + mk_string(t); } &&
requires(T t) {
{mk_string(t)} -> same_as<string>;
};
string dbl_quote(const dbl_quotable auto& val) {
auto val2{val}; // Kopie erzeugen (nur zu Demozwecken)
return '"' + mk_string(val) + mk_string(val2) + '"';
}
Godbolt Listing lst-0648-godb.cpp, https://godbolt.org/z/Tcxnr6jTM:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Tcxnr6jTM
template<typename T>
concept dbl_quotable = copyable<T> &&
requires (T t) { mk_string(t) + mk_string(t); } &&
requires(T t) {
{mk_string(t)} -> same_as<string>;
};
string dbl_quote(const dbl_quotable auto& val) {
auto val2{val}; // Kopie erzeugen (nur zu Demozwecken)
return '"' + mk_string(val) + mk_string(val2) + '"';
}
GodboltId:9qsGW6M8Y
Book listing lst-0649-book.cpp:
// https://godbolt.org/z/9qsGW6M8Y
template<std::ranges::range T> // eine Range über Typ T
using ValueTypeOfRange = std::ranges::range_value_t<T>;
// oder
template<typename T>
requires std::ranges::range<T> // eine Range über Typ T
using ValueTypeOfRange = std::ranges::range_value_t<T>;
// ergibt:
ValueTypeOfRange<std::vector<int>> x; // x ist int
ValueTypeOfRange<std::string> y; // y ist char
ValueTypeOfRange<std::list<double>> z; // z ist double
ValueTypeOfRange<int> w; // (ERR) int ist keine Range
Godbolt Listing lst-0649-godb.cpp, https://godbolt.org/z/9qsGW6M8Y:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/9qsGW6M8Y
template<std::ranges::range T> // eine Range über Typ T
using ValueTypeOfRange = std::ranges::range_value_t<T>;
// oder
template<typename T>
requires std::ranges::range<T> // eine Range über Typ T
using ValueTypeOfRange = std::ranges::range_value_t<T>;
// ergibt:
ValueTypeOfRange<std::vector<int>> x; // x ist int
ValueTypeOfRange<std::string> y; // y ist char
ValueTypeOfRange<std::list<double>> z; // z ist double
ValueTypeOfRange<int> w; // (ERR) int ist keine Range
Listing 23.28: So verwenden Sie Concepts in einem constexpr if.
Book listing lst-0650-book.cpp:
if constexpr std::integral<T> {
// T ist ein integraler Typ
} else if constexpr std::floating_point<T> {
// T ist ein Gleitkommatyp
} else {
// T ist weder noch
}
Listing 23.29: Ein Klassentemplate erhält einen Typ als formalen Parameter.
Book listing lst-0654-book.cpp:
// https://godbolt.org/z/jqzTMxYKv
template <std::copyable T> // C++20-Concept
class MyContainer {
T data_;
public:
void setData(const T& d) { data_ = d; }
T getData() const { return data_; }
};
Godbolt Listing lst-0654-godb.cpp, https://godbolt.org/z/jqzTMxYKv:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/jqzTMxYKv
template <std::copyable T> // C++20-Concept
class MyContainer {
T data_;
public:
void setData(const T& d) { data_ = d; }
T getData() const { return data_; }
};
Listing 23.30: Methodendefinitionen außerhalb des Körpers eines Klassentemplates sind syntaktisch etwas aufwendiger.
Book listing lst-0656-book.cpp:
// https://godbolt.org/z/4fK5WdoG8
template <std::copyable T>
class MyContainer {
T data_;
public:
void setData(const T& d);
T getData() const;
};
template <std::copyable T>
void MyContainer<T>::setData(const T& d) {
data_ = d;
}
template <std::copyable T>
T MyContainer<T>::getData() const {
return data_;
}
Godbolt Listing lst-0656-godb.cpp, https://godbolt.org/z/4fK5WdoG8:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/4fK5WdoG8
template <std::copyable T>
class MyContainer {
T data_;
public:
void setData(const T& d);
T getData() const;
};
template <std::copyable T>
void MyContainer<T>::setData(const T& d) {
data_ = d;
}
template <std::copyable T>
T MyContainer<T>::getData() const {
return data_;
}
Listing 23.31: Klassentemplate-Methoden wie Funktionstemplates spezialisieren.
Book listing lst-0657-book.cpp:
// https://godbolt.org/z/M6earoWMn
#include <iostream>
#include <string>
#include <concepts> // copyable, C++20
template <std::copyable T>
class MyContainer {
T data_;
public:
void setData(const T& d) { data_ = d; } // allgemeiner Fall
T getData() const { return data_; } // allgemeiner Fall
};
template<> // Spezialisierung
void MyContainer<std::string>::setData(const std::string& d) {
data_ = "[" + d + "]";
}
int main() {
MyContainer<std::string> mcString;
mcString.setData("Geschichte");
std::cout << mcString.getData() << '\n'; // Ausgabe: [Geschichte]
MyContainer<int> mcInt;
mcInt.setData(5);
std::cout << mcInt.getData() << '\n'; // Ausgabe: 5
}
Godbolt Listing lst-0657-godb.cpp, https://godbolt.org/z/M6earoWMn:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/M6earoWMn
#include <iostream>
#include <string>
#include <concepts> // copyable, C++20
template <std::copyable T>
class MyContainer {
T data_;
public:
void setData(const T& d) { data_ = d; } // allgemeiner Fall
T getData() const { return data_; } // allgemeiner Fall
};
template<> // Spezialisierung
void MyContainer<std::string>::setData(const std::string& d) {
data_ = "[" + d + "]";
}
int main() {
MyContainer<std::string> mcString;
mcString.setData("Geschichte");
std::cout << mcString.getData() << '\n'; // Ausgabe: [Geschichte]
MyContainer<int> mcInt;
mcInt.setData(5);
std::cout << mcInt.getData() << '\n'; // Ausgabe: 5
}
Listing 23.32: So erzeugen Sie Instanzen aus einer Templateklasse.
Book listing lst-0658-book.cpp:
// https://godbolt.org/z/9vP3o68bW
#include <iostream>
#include <string>
#include <concepts> // copyable, C++20
template <std::copyable T>
class MyContainer {
T data_;
public:
void setData(const T& d) { data_ = d; }
T getData() const { return data_; }
};
class IntValue {
int val_;
public:
explicit IntValue(int val=0) : val_(val) {}
int getInt() const { return val_; }
};
int main() {
// C-Array mit drei MyContainer<double>-Instanzen
MyContainer<double> dcont[3];
dcont[0].setData(123.123);
dcont[1].setData(234.234);
std::cout << dcont[0].getData() << std::endl;
std::cout << dcont[1].getData() << std::endl;
// eigener Datentyp als formaler Parameter
IntValue ival{100'000};
MyContainer<IntValue> scont;
scont.setData(ival);
std::cout << scont.getData().getInt() << std::endl;
// string als formaler Parameter
std::string str("Text");
MyContainer<std::string> strCont;
strCont.setData(str);
std::cout << strCont.getData() << std::endl;
}
Godbolt Listing lst-0658-godb.cpp, https://godbolt.org/z/9vP3o68bW:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/9vP3o68bW
#include <iostream>
#include <string>
#include <concepts> // copyable, C++20
template <std::copyable T>
class MyContainer {
T data_;
public:
void setData(const T& d) { data_ = d; }
T getData() const { return data_; }
};
class IntValue {
int val_;
public:
explicit IntValue(int val=0) : val_(val) {}
int getInt() const { return val_; }
};
int main() {
// C-Array mit drei MyContainer<double>-Instanzen
MyContainer<double> dcont[3];
dcont[0].setData(123.123);
dcont[1].setData(234.234);
std::cout << dcont[0].getData() << std::endl;
std::cout << dcont[1].getData() << std::endl;
// eigener Datentyp als formaler Parameter
IntValue ival{100'000};
MyContainer<IntValue> scont;
scont.setData(ival);
std::cout << scont.getData().getInt() << std::endl;
// string als formaler Parameter
std::string str("Text");
MyContainer<std::string> strCont;
strCont.setData(str);
std::cout << strCont.getData() << std::endl;
}
Listing 23.33: Aus Konstruktorargumenten auf Templateparameter schließen
Book listing lst-0659-book.cpp:
// https://godbolt.org/z/7KzcWE8Pz
#include <string>
#include <vector>
#include <set>
#include <tuple>
#include <memory> // shared_ptr
template <typename T>
class MyStuff {
T data_;
public:
MyStuff() : data_{} {} // default c'tor
MyStuff(const T& d) : data_{d} { } // copy c'tor
T getStuff() const { return data_; }
};
class IntValue {
int val_;
public:
explicit IntValue(int val=0) : val_(val) {}
int getInt() const { return val_; }
};
int main() {
MyStuff intStuff(12); // wird zu MyStuff<int>
std::vector vs{ 1,2,3,4 }; // wird zu vector<int>
MyStuff ivalStuff{ IntValue{33} }; // wird zu MyStuff<IntValue>
std::tuple tpl{ 23, 'a' }; // wird zu tuple<int,char>
std::set zweiDrei (vs.begin()+1, vs.end()-1); // wird zu set<int>
// Kann der Compiler nicht deduzieren:
MyStuff<double> dblStuff; // kein Konstruktorargument
std::vector<char> vcs(10); // Größe 10, aber von welchem Typ?
std::shared_ptr<int> ptr{new int{88}}; // keine Regel für int*
}
Godbolt Listing lst-0659-godb.cpp, https://godbolt.org/z/7KzcWE8Pz:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/7KzcWE8Pz
#include <string>
#include <vector>
#include <set>
#include <tuple>
#include <memory> // shared_ptr
template <typename T>
class MyStuff {
T data_;
public:
MyStuff() : data_{} {} // default c'tor
MyStuff(const T& d) : data_{d} { } // copy c'tor
T getStuff() const { return data_; }
};
class IntValue {
int val_;
public:
explicit IntValue(int val=0) : val_(val) {}
int getInt() const { return val_; }
};
int main() {
MyStuff intStuff(12); // wird zu MyStuff<int>
std::vector vs{ 1,2,3,4 }; // wird zu vector<int>
MyStuff ivalStuff{ IntValue{33} }; // wird zu MyStuff<IntValue>
std::tuple tpl{ 23, 'a' }; // wird zu tuple<int,char>
std::set zweiDrei (vs.begin()+1, vs.end()-1); // wird zu set<int>
// Kann der Compiler nicht deduzieren:
MyStuff<double> dblStuff; // kein Konstruktorargument
std::vector<char> vcs(10); // Größe 10, aber von welchem Typ?
std::shared_ptr<int> ptr{new int{88}}; // keine Regel für int*
}
Listing 23.34: Sie können make_-Hilfsfunktionen und auto schon lange verwenden.
Book listing lst-0660-book.cpp:
auto tpl = std::make_tuple( 5, 'x' );
auto ptr = std::make_shared( 5 );
GodboltId:dMTnbT1v4
Book listing lst-0661-book.cpp:
// https://godbolt.org/z/dMTnbT1v4
#include <iostream>
#include <concepts> // copyable, C+20
template<std::copyable T, std::copyable U>
class MyPair {
T data01_;
U data02_;
public:
MyPair(const T& t,const U& u) : data01_{t}, data02_{u} {}
void print(std::ostream& os) const {
os << data01_ << " : " << data02_ << std::endl;
}
};
int main() {
std::string month{"Januar"};
int temp = -5;
MyPair<std::string, int> temperatur{month, temp};
temperatur.print(std::cout);
}
Godbolt Listing lst-0661-godb.cpp, https://godbolt.org/z/dMTnbT1v4:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/dMTnbT1v4
#include <iostream>
#include <concepts> // copyable, C+20
template<std::copyable T, std::copyable U>
class MyPair {
T data01_;
U data02_;
public:
MyPair(const T& t,const U& u) : data01_{t}, data02_{u} {}
void print(std::ostream& os) const {
os << data01_ << " : " << data02_ << std::endl;
}
};
int main() {
std::string month{"Januar"};
int temp = -5;
MyPair<std::string, int> temperatur{month, temp};
temperatur.print(std::cout);
}
GodboltId:jbafeEdoW
Book listing lst-0662-book.cpp:
// https://godbolt.org/z/jbafeEdoW
#include <iostream>
#include <concepts> // copyable, C++20
template<std::copyable T, std::copyable U=T>
class MyPair {
T data01_;
U data02_;
public:
MyPair(const T& t,const U& u) : data01_{t}, data02_{u} {}
void print(std::ostream& os) const {
os << data01_ << " : " << data02_ << std::endl;
}
};
int main() {
MyPair<double> zahlen{11.11, 22.22};
zahlen.print(std::cout);
}
Godbolt Listing lst-0662-godb.cpp, https://godbolt.org/z/jbafeEdoW:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/jbafeEdoW
#include <iostream>
#include <concepts> // copyable, C++20
template<std::copyable T, std::copyable U=T>
class MyPair {
T data01_;
U data02_;
public:
MyPair(const T& t,const U& u) : data01_{t}, data02_{u} {}
void print(std::ostream& os) const {
os << data01_ << " : " << data02_ << std::endl;
}
};
int main() {
MyPair<double> zahlen{11.11, 22.22};
zahlen.print(std::cout);
}
GodboltId:xPrheoeEd
Book listing lst-0665-book.cpp:
// https://godbolt.org/z/xPrheoeEd
#include <iostream>
template <typename T, size_t n=1> // Non-Type-Parameter mit Defaultwert
class FixedArray {
T data_[n] {0}; // Non-Type-Parameter verwenden
public:
T& operator[](size_t index) { return data_[index]; }
static constexpr size_t size() { return n; }
void print(std::ostream &os) const {
for(auto it : data_)
os << it << ' ';
os << '\n';
}
};
int main() {
FixedArray<int,10> vals {}; // n = 10
for(size_t idx=0; idx < vals.size(); ++idx) {
vals[idx] = idx+idx;
}
vals.print(std::cout); // Ausgabe: 0 2 4 6 8 10 12 14 16 18
FixedArray<double> dvals; // Defaultparameter für n
std::cout << dvals.size() << '\n'; // Ausgabe: 1
}
Godbolt Listing lst-0665-godb.cpp, https://godbolt.org/z/xPrheoeEd:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/xPrheoeEd
#include <iostream>
template <typename T, size_t n=1> // Non-Type-Parameter mit Defaultwert
class FixedArray {
T data_[n] {0}; // Non-Type-Parameter verwenden
public:
T& operator[](size_t index) { return data_[index]; }
static constexpr size_t size() { return n; }
void print(std::ostream &os) const {
for(auto it : data_)
os << it << ' ';
os << '\n';
}
};
int main() {
FixedArray<int,10> vals {}; // n = 10
for(size_t idx=0; idx < vals.size(); ++idx) {
vals[idx] = idx+idx;
}
vals.print(std::cout); // Ausgabe: 0 2 4 6 8 10 12 14 16 18
FixedArray<double> dvals; // Defaultparameter für n
std::cout << dvals.size() << '\n'; // Ausgabe: 1
}
GodboltId:Y6v6cKE3v
Book listing lst-0670-book.cpp:
// https://godbolt.org/z/Y6v6cKE3v
#include <string>
#include <tuple>
#include <concepts> // copyable, C++20
template <std::copyable T, std::copyable U=T> // allgemeiner Fall
class MyPair {
T data01_;
U data02_;
public:
MyPair(const T& t, const U& u) : data01_{t}, data02_{u} {}
};
template <std::copyable T> // teilweise Spezialisierung, T bleibt formal
class MyPair<T, std::string> { // U ist auf string spezialisiert
std::tuple<T,std::string> data_;
public:
MyPair(const T& t, const std::string& str) : data_{t, str} { }
};
template <std::copyable U> // teilweise Spezialisierung, U bleibt formal
class MyPair<std::string, U> { // T ist auf string spezialisiert
std::tuple<std::string, U> data_;
public:
MyPair(const std::string& str, const U& u) : data_{str, u} { }
};
int main() {
// nutzt partielle Spezialisierung
MyPair<int,std::string> intString{1, "a"};
MyPair<std::string,int> stringInt{"b", 2};
MyPair<int,int> intInt{3,4}; // nutzt allgemeinen Fall
MyPair intInt2{3,4}; // auch MyPair<int,int>
MyPair<std::string,std::string> strStr{"c","d"}; // (ERR) mehrdeutig
}
Godbolt Listing lst-0670-godb.cpp, https://godbolt.org/z/Y6v6cKE3v:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Y6v6cKE3v
#include <string>
#include <tuple>
#include <concepts> // copyable, C++20
template <std::copyable T, std::copyable U=T> // allgemeiner Fall
class MyPair {
T data01_;
U data02_;
public:
MyPair(const T& t, const U& u) : data01_{t}, data02_{u} {}
};
template <std::copyable T> // teilweise Spezialisierung, T bleibt formal
class MyPair<T, std::string> { // U ist auf string spezialisiert
std::tuple<T,std::string> data_;
public:
MyPair(const T& t, const std::string& str) : data_{t, str} { }
};
template <std::copyable U> // teilweise Spezialisierung, U bleibt formal
class MyPair<std::string, U> { // T ist auf string spezialisiert
std::tuple<std::string, U> data_;
public:
MyPair(const std::string& str, const U& u) : data_{str, u} { }
};
int main() {
// nutzt partielle Spezialisierung
MyPair<int,std::string> intString{1, "a"};
MyPair<std::string,int> stringInt{"b", 2};
MyPair<int,int> intInt{3,4}; // nutzt allgemeinen Fall
MyPair intInt2{3,4}; // auch MyPair<int,int>
MyPair<std::string,std::string> strStr{"c","d"}; // (ERR) mehrdeutig
}
GodboltId:baPeoTbM8
Book listing lst-0671-book.cpp:
// https://godbolt.org/z/baPeoTbM8
template<> // vollständige Spezialisierung
class MyPair<std::string, std::string> {
std::vector<std::string> data_;
public:
MyPair(const std::string& t, const std::string& u) : data_{t, u} { }
};
int main() {
// nutzt die vollständige Spezialisierung:
MyPair<std::string,std::string> strStr{"c","d"};
}
Godbolt Listing lst-0671-godb.cpp, https://godbolt.org/z/baPeoTbM8:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/baPeoTbM8
template<> // vollständige Spezialisierung
class MyPair<std::string, std::string> {
std::vector<std::string> data_;
public:
MyPair(const std::string& t, const std::string& u) : data_{t, u} { }
};
int main() {
// nutzt die vollständige Spezialisierung:
MyPair<std::string,std::string> strStr{"c","d"};
}
Listing 23.35: Ein Template mit einer variablen Anzahl von Argumenten
Book listing lst-0672-book.cpp:
// https://godbolt.org/z/c6W6EWb1K
#include <typeinfo> // operator typeid
#include <typeindex> // type_index
#include <map>
#include <string>
#include <iostream>
template <typename T>
void output(std::ostream& os, T val) { // einen Typnamen ausgeben
// static: beim ersten Mal initialisiert
static const std::map<std::type_index,std::string> type_names {
{ std::type_index(typeid(const char*)), "const char*"},
{ std::type_index(typeid(char)), "char"},
{ std::type_index(typeid(int)), "int"},
{ std::type_index(typeid(double)), "double"},
{ std::type_index(typeid(bool)), "bool"},
};
const std::string name = type_names.at(std::type_index(typeid(T)));
os << name << ": " << val << '\n';
}
// rekursives variadisches Funktionstemplate:
template<typename First, typename ... Rest>
void output(std::ostream &os, First first, Rest ... rest) {
output(os, first); // einzelner Aufruf mit vorderstem Element
output(os, rest ...); // Rekursion mit Rest der Elemente
}
int main() {
output(std::cout, 3.1415); // normales Template
output(std::cout, "ende", 2, 3.14, 'A', false); // rekursive variadische Funktion
}
Godbolt Listing lst-0672-godb.cpp, https://godbolt.org/z/c6W6EWb1K:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/c6W6EWb1K
#include <typeinfo> // operator typeid
#include <typeindex> // type_index
#include <map>
#include <string>
#include <iostream>
template <typename T>
void output(std::ostream& os, T val) { // einen Typnamen ausgeben
// static: beim ersten Mal initialisiert
static const std::map<std::type_index,std::string> type_names {
{ std::type_index(typeid(const char*)), "const char*"},
{ std::type_index(typeid(char)), "char"},
{ std::type_index(typeid(int)), "int"},
{ std::type_index(typeid(double)), "double"},
{ std::type_index(typeid(bool)), "bool"},
};
const std::string name = type_names.at(std::type_index(typeid(T)));
os << name << ": " << val << '\n';
}
// rekursives variadisches Funktionstemplate:
template<typename First, typename ... Rest>
void output(std::ostream &os, First first, Rest ... rest) {
output(os, first); // einzelner Aufruf mit vorderstem Element
output(os, rest ...); // Rekursion mit Rest der Elemente
}
int main() {
output(std::cout, 3.1415); // normales Template
output(std::cout, "ende", 2, 3.14, 'A', false); // rekursive variadische Funktion
}
GodboltId:8oYaWYnbx
Book listing lst-0678-book.cpp:
// https://godbolt.org/z/8oYaWYnbx
#include <tuple>
#include <iostream>
template<typename ... Args>
auto conv2tuple(Args ... args) {
return std::make_tuple(args...);
}
int main() {
auto mytuple = conv2tuple("ende", 2, 3.14, 'A', false);
std::cout << std::get<2>(mytuple) << '\n'; // Ausgabe: 3.14
}
Godbolt Listing lst-0678-godb.cpp, https://godbolt.org/z/8oYaWYnbx:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/8oYaWYnbx
#include <tuple>
#include <iostream>
template<typename ... Args>
auto conv2tuple(Args ... args) {
return std::make_tuple(args...);
}
int main() {
auto mytuple = conv2tuple("ende", 2, 3.14, 'A', false);
std::cout << std::get<2>(mytuple) << '\n'; // Ausgabe: 3.14
}
Listing 23.36: Eigene Literaloperatoren
Book listing lst-0679-book.cpp:
// https://godbolt.org/z/cjx49ef19
namespace my {
Complex operator"" _i(const char*); // 0+ni
Complex operator"" _j(long double); // n+0i
Puzzle operator"" _puzzle(const char*, size_t);
}
using namespace my;
Complex imag4 = 4_i; // operator"" _i(const char*)
Complex real3 = 3.331_j; // operator"" _j(long double)
Puzzle p1 = "oXo" // operator"" _puzzle(const char*, size_t)
"XoX"_puzzle;
Godbolt Listing lst-0679-godb.cpp, https://godbolt.org/z/cjx49ef19:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/cjx49ef19
namespace my {
Complex operator"" _i(const char*); // 0+ni
Complex operator"" _j(long double); // n+0i
Puzzle operator"" _puzzle(const char*, size_t);
}
using namespace my;
Complex imag4 = 4_i; // operator"" _i(const char*)
Complex real3 = 3.331_j; // operator"" _j(long double)
Puzzle p1 = "oXo" // operator"" _puzzle(const char*, size_t)
"XoX"_puzzle;
Listing 23.37: Welches Literal führt zu welchem Operatoraufruf?
Book listing lst-0680-book.cpp:
// https://godbolt.org/z/Mevoshb3o
namespace lits {
long double operator"" _w(long double);
string operator"" _w(const char16_t*, size_t);
unsigned operator"" _w(const char*);
}
int main() {
using namespace lits;
1.2_w; // operator"" _w(long double), mit (1.2L)
u"one"_w; // operator"" _w(char16_t, size_t), mit (u"one", 3)
12_w; // operator"" _w(const char*), mit "12"
"two"_w; // (ERR) operator"" _w(const char*, size_t) nicht definiert
}
Godbolt Listing lst-0680-godb.cpp, https://godbolt.org/z/Mevoshb3o:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Mevoshb3o
namespace lits {
long double operator"" _w(long double);
string operator"" _w(const char16_t*, size_t);
unsigned operator"" _w(const char*);
}
int main() {
using namespace lits;
1.2_w; // operator"" _w(long double), mit (1.2L)
u"one"_w; // operator"" _w(char16_t, size_t), mit (u"one", 3)
12_w; // operator"" _w(const char*), mit "12"
"two"_w; // (ERR) operator"" _w(const char*, size_t) nicht definiert
}
Listing 23.38: Ein Template für Literale der exakten Länge zwei
Book listing lst-0681-book.cpp:
// https://godbolt.org/z/5rdzn8YP4
namespace lits {
// allgemeines Template
template<char...> int operator"" _bin2();
// Spezialisierungen
template<> int operator"" _bin2<'0','0'>() { return 0; }
template<> int operator"" _bin2<'0','1'>() { return 1; }
template<> int operator"" _bin2<'1','0'>() { return 2; }
template<> int operator"" _bin2<'1','1'>() { return 3; }
}
int main() {
using namespace lits;
int one = 01_bin2;
int three = 11_bin2;
}
Godbolt Listing lst-0681-godb.cpp, https://godbolt.org/z/5rdzn8YP4:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/5rdzn8YP4
namespace lits {
// allgemeines Template
template<char...> int operator"" _bin2();
// Spezialisierungen
template<> int operator"" _bin2<'0','0'>() { return 0; }
template<> int operator"" _bin2<'0','1'>() { return 1; }
template<> int operator"" _bin2<'1','0'>() { return 2; }
template<> int operator"" _bin2<'1','1'>() { return 3; }
}
int main() {
using namespace lits;
int one = 01_bin2;
int three = 11_bin2;
}
Listing 23.39: Rekursive Definition für beliebige Literallängen
Book listing lst-0682-book.cpp:
// https://godbolt.org/z/sbxojqjqs
namespace lits {
// Templatehilfsfunktion für ein Argument
template<char C> int bin(); // allgemeiner Fall
template<> int bin<'1'>() { return 1; } // Spezialisierung.
template<> int bin<'0'>() { return 0; } // Spezialisierung.
// Templatehilfsfunktion ab zwei Argumente
template<char C, char D, char... ES>
int bin() {
return bin<C>() << (sizeof...(ES)+1) | bin<D,ES...>(); // Bit-Shift, Bit-Oder
}
// eigentlicher operator""
template<char...CS> int operator"" _bin()
{ return bin<CS...>(); };
}
int main() {
using namespace lits;
int eins = 1_bin;
int acht = 1000_bin;
int neun = 1001_bin;
int zehn = 1010_bin;
int elf = 1011_bin;
int hundertachtundzwanzig = 10000000_bin;
}
Godbolt Listing lst-0682-godb.cpp, https://godbolt.org/z/sbxojqjqs:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/sbxojqjqs
namespace lits {
// Templatehilfsfunktion für ein Argument
template<char C> int bin(); // allgemeiner Fall
template<> int bin<'1'>() { return 1; } // Spezialisierung.
template<> int bin<'0'>() { return 0; } // Spezialisierung.
// Templatehilfsfunktion ab zwei Argumente
template<char C, char D, char... ES>
int bin() {
return bin<C>() << (sizeof...(ES)+1) | bin<D,ES...>(); // Bit-Shift, Bit-Oder
}
// eigentlicher operator""
template<char...CS> int operator"" _bin()
{ return bin<CS...>(); };
}
int main() {
using namespace lits;
int eins = 1_bin;
int acht = 1000_bin;
int neun = 1001_bin;
int zehn = 1010_bin;
int elf = 1011_bin;
int hundertachtundzwanzig = 10000000_bin;
}
Listing 23.40: Das neue if constexpr spart Funktionsspezialisierungen.
Book listing lst-0683-book.cpp:
// https://godbolt.org/z/KvsGh4f1v
namespace lits {
// Templatehilfsfunktion für ein Argument
template<char C> int bin() { // allgemeiner Fall
if constexpr (C=='0') return 0;
else if constexpr (C=='1') return 1;
}
// Templatehilfsfunktion ab zwei Argumente
// …
}
Godbolt Listing lst-0683-godb.cpp, https://godbolt.org/z/KvsGh4f1v:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/KvsGh4f1v
namespace lits {
// Templatehilfsfunktion für ein Argument
template<char C> int bin() { // allgemeiner Fall
if constexpr (C=='0') return 0;
else if constexpr (C=='1') return 1;
}
// Templatehilfsfunktion ab zwei Argumente
// …
}
Listing 23.41: Mit Faltausdrücken werden variadische Templates einfacher.
Book listing lst-0684-book.cpp:
// https://godbolt.org/z/cPoEjqzM7
#include <iostream>
#include <string>
namespace lits {
// operator"" _sx
template<char...CS> std::string operator"" _sx() {
return (std::string{} + ... + CS); // ein Faltausdruck
};
}
int main() {
using namespace lits;
std::cout << 10000000_sx << '\n'; // Ausgabe: 10000000
std::cout << 10'000'000_sx << '\n'; // Ausgabe: 10'000'000
std::cout << 0x00af_sx << '\n'; // Ausgabe: 0x00af
std::cout << 0x0'c'0'a'f_sx << '\n'; // Ausgabe: 0x0'c'0'a'f
std::cout << 007_sx << '\n'; // Ausgabe: 007
std::cout << 0b01_sx << '\n'; // Ausgabe: 0b01
}
Godbolt Listing lst-0684-godb.cpp, https://godbolt.org/z/cPoEjqzM7:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/cPoEjqzM7
#include <iostream>
#include <string>
namespace lits {
// operator"" _sx
template<char...CS> std::string operator"" _sx() {
return (std::string{} + ... + CS); // ein Faltausdruck
};
}
int main() {
using namespace lits;
std::cout << 10000000_sx << '\n'; // Ausgabe: 10000000
std::cout << 10'000'000_sx << '\n'; // Ausgabe: 10'000'000
std::cout << 0x00af_sx << '\n'; // Ausgabe: 0x00af
std::cout << 0x0'c'0'a'f_sx << '\n'; // Ausgabe: 0x0'c'0'a'f
std::cout << 007_sx << '\n'; // Ausgabe: 007
std::cout << 0b01_sx << '\n'; // Ausgabe: 0b01
}
Listing 23.42: Ob vorverarbeitet oder roh besser ist, hängt von der Anwendung ab.
Book listing lst-0685-book.cpp:
// https://godbolt.org/z/Yd4sser5j
#include <complex>
// rohe Form
int operator"" _dual(const char*);
int answer = 101010_dual; // dezimal 42
// vorverarbeitete Form
std::complex<long double> operator"" _i(long double d) {
return std::complex<long double>(0, d);
}
auto val = 3.14_i; // val = std::complex<long double>(0, 3.14)
Godbolt Listing lst-0685-godb.cpp, https://godbolt.org/z/Yd4sser5j:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Yd4sser5j
#include <complex>
// rohe Form
int operator"" _dual(const char*);
int answer = 101010_dual; // dezimal 42
// vorverarbeitete Form
std::complex<long double> operator"" _i(long double d) {
return std::complex<long double>(0, d);
}
auto val = 3.14_i; // val = std::complex<long double>(0, 3.14)
Listing 24.1: Für Bereiche nutzen Sie Iteratorpaare oder ab C++23 Ranges.
Book listing lst-0694-book.cpp:
// https://godbolt.org/z/qGrYPrqYn
#include <vector>
#include <iostream>
using namespace std;
int main() {
vector nums{ 1,2,3 };
vector vier{ 4,5,6 };
vector sieben{ 7,8,9 } ;
nums.insert(nums.begin(), vier.begin(), vier.end());
cout << nums.size() << "\n"; // Ausgabe: 9
nums.insert_range(nums.begin(), sieben); // C++23
}
Godbolt Listing lst-0694-godb.cpp, https://godbolt.org/z/qGrYPrqYn:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/qGrYPrqYn
#include <vector>
#include <iostream>
using namespace std;
int main() {
vector nums{ 1,2,3 };
vector vier{ 4,5,6 };
vector sieben{ 7,8,9 } ;
nums.insert(nums.begin(), vier.begin(), vier.end());
cout << nums.size() << "\n"; // Ausgabe: 9
nums.insert_range(nums.begin(), sieben); // C++23
}
Listing 24.2: Ein Paar Iteratoren definiert einen Bereich von Elementen.
Book listing lst-0695-book.cpp:
// https://godbolt.org/z/M1d9jEP74
#include <vector>
#include <iostream>
using namespace std;
int main() {
vector numbers{ 1,2,3,4,5 };
numbers.erase(numbers.begin(), numbers.end());
cout << numbers.size() << "\n"; // Ausgabe: 0
}
Godbolt Listing lst-0695-godb.cpp, https://godbolt.org/z/M1d9jEP74:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/M1d9jEP74
#include <vector>
#include <iostream>
using namespace std;
int main() {
vector numbers{ 1,2,3,4,5 };
numbers.erase(numbers.begin(), numbers.end());
cout << numbers.size() << "\n"; // Ausgabe: 0
}
Listing 24.3: Verwendet indirekt begin() und end() des Containers
Book listing lst-0696-book.cpp:
// https://godbolt.org/z/Yv3vcxPv5
#include <vector>
#include <iostream>
int main() {
std::vector<int> numbers{ 1,2,3,4,5 };
for(auto val : numbers) {
std::cout << val << ' ';
}
std::cout << '\n';
}
Godbolt Listing lst-0696-godb.cpp, https://godbolt.org/z/Yv3vcxPv5:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Yv3vcxPv5
#include <vector>
#include <iostream>
int main() {
std::vector<int> numbers{ 1,2,3,4,5 };
for(auto val : numbers) {
std::cout << val << ' ';
}
std::cout << '\n';
}
GodboltId:babK485oT
Book listing lst-0697-book.cpp:
// https://godbolt.org/z/babK485oT
#include <vector>
#include <iostream>
int main() {
std::vector<int> numbers{ 1,2,3,4,5 };
for(auto it = begin(numbers); it != end(numbers); ++it) {
auto val = *it;
std::cout << val << ' ';
}
std::cout << '\n';
}
Godbolt Listing lst-0697-godb.cpp, https://godbolt.org/z/babK485oT:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/babK485oT
#include <vector>
#include <iostream>
int main() {
std::vector<int> numbers{ 1,2,3,4,5 };
for(auto it = begin(numbers); it != end(numbers); ++it) {
auto val = *it;
std::cout << val << ' ';
}
std::cout << '\n';
}
GodboltId:nj14e6Wq4
Book listing lst-0698-book.cpp:
// https://godbolt.org/z/nj14e6Wq4
#include <set>
#include <iostream>
int main() {
std::set<int> numbers{ 10, 20, 90 };
auto nein = numbers.find(30);
if(nein == numbers.end()) { std::cout << "nicht da.\n"; }
auto ja = numbers.find(20);
if(ja != numbers.end()) { std::cout << *ja << '\n'; }
}
Godbolt Listing lst-0698-godb.cpp, https://godbolt.org/z/nj14e6Wq4:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/nj14e6Wq4
#include <set>
#include <iostream>
int main() {
std::set<int> numbers{ 10, 20, 90 };
auto nein = numbers.find(30);
if(nein == numbers.end()) { std::cout << "nicht da.\n"; }
auto ja = numbers.find(20);
if(ja != numbers.end()) { std::cout << *ja << '\n'; }
}
Listing 24.4: Ein Algorithmus nach dem anderen mit Iteratoren
Book listing lst-0699-book.cpp:
// https://godbolt.org/z/arfee3TTP
using namespace std;
vector in { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
vector<int> tmp{};
vector<int> out{};
copy_if(in.begin(), in.end(), back_inserter(tmp), [](int i) { return i%3 == 0; });
transform(tmp.begin(), tmp.end(), back_inserter(out), [](int i) {return i*i; });
Godbolt Listing lst-0699-godb.cpp, https://godbolt.org/z/arfee3TTP:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/arfee3TTP
using namespace std;
vector in { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
vector<int> tmp{};
vector<int> out{};
copy_if(in.begin(), in.end(), back_inserter(tmp), [](int i) { return i%3 == 0; });
transform(tmp.begin(), tmp.end(), back_inserter(out), [](int i) {return i*i; });
Listing 24.5: Eine Pipeline aus Views statt Algorithmen
Book listing lst-0700-book.cpp:
// https://godbolt.org/z/TG1qd31Mq
using namespace std; namespace views = std::ranges::views;
vector in { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
auto out = in
| views::filter([](int i) { return i%3 == 0; })
| views::transform([](int i) {return i*i; });
Godbolt Listing lst-0700-godb.cpp, https://godbolt.org/z/TG1qd31Mq:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/TG1qd31Mq
using namespace std; namespace views = std::ranges::views;
vector in { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
auto out = in
| views::filter([](int i) { return i%3 == 0; })
| views::transform([](int i) {return i*i; });
Listing 24.8: Für »const«-Objekte liefern »begin()« und »end()« einen »const_iterator« zurück.
Book listing lst-0702-book.cpp:
// https://godbolt.org/z/dxb98rWzo
#include <iostream> // cout
#include <vector>
using std::vector;
vector<int> createData(size_t sz) {
return vector<int>(sz); // sz x null
}
void fibonacci(vector<int> &data) {
for(auto it = begin(data)+2; it != end(data); ++it) { // iterator it
*it = *(it-1) + *(it-2);
}
}
std::ostream& show(std::ostream &os, const vector<int> &data) {
for(auto it=begin(data); it != end(data); ++it) // const_iterator it
std::cout << *it << " ";
return os;
}
int main() {
vector<int> data = createData(10);
data[0] = 1;
data[1] = 1;
fibonacci(data);
show(std::cout, data) << "\n";
}
Godbolt Listing lst-0702-godb.cpp, https://godbolt.org/z/dxb98rWzo:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/dxb98rWzo
#include <iostream> // cout
#include <vector>
using std::vector;
vector<int> createData(size_t sz) {
return vector<int>(sz); // sz x null
}
void fibonacci(vector<int> &data) {
for(auto it = begin(data)+2; it != end(data); ++it) { // iterator it
*it = *(it-1) + *(it-2);
}
}
std::ostream& show(std::ostream &os, const vector<int> &data) {
for(auto it=begin(data); it != end(data); ++it) // const_iterator it
std::cout << *it << " ";
return os;
}
int main() {
vector<int> data = createData(10);
data[0] = 1;
data[1] = 1;
fibonacci(data);
show(std::cout, data) << "\n";
}
Listing 24.9: Iteratoradapter verändern das Verhalten von Operationen.
Book listing lst-0706-book.cpp:
// https://godbolt.org/z/7xYcqqh68
#include <vector>
#include <iostream> // cout
#include <iterator> // ostream_iterator
#include <algorithm> // copy
int main() {
std::vector data { 1, 2, 3, 7, 9, 10 };
std::ostream_iterator<int> out_it (std::cout,", "); // bei Zuweisung nach cout
std::copy(data.begin(), data.end(), out_it); // alle Elemente in den Iterator
std::cout << "\n"; // Ausgabe: 1, 2, 3, 7, 9, 10,
// oder ab C++20 mit Ranges:
std::ranges::copy(data, out_it);
std::cout << "\n"; // Ausgabe: 1, 2, 3, 7, 9, 10,
}
Godbolt Listing lst-0706-godb.cpp, https://godbolt.org/z/7xYcqqh68:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/7xYcqqh68
#include <vector>
#include <iostream> // cout
#include <iterator> // ostream_iterator
#include <algorithm> // copy
int main() {
std::vector data { 1, 2, 3, 7, 9, 10 };
std::ostream_iterator<int> out_it (std::cout,", "); // bei Zuweisung nach cout
std::copy(data.begin(), data.end(), out_it); // alle Elemente in den Iterator
std::cout << "\n"; // Ausgabe: 1, 2, 3, 7, 9, 10,
// oder ab C++20 mit Ranges:
std::ranges::copy(data, out_it);
std::cout << "\n"; // Ausgabe: 1, 2, 3, 7, 9, 10,
}
Listing 24.10: Ein (zu) einfacher Allokator und sein Einsatz
Book listing lst-0707-book.cpp:
// https://godbolt.org/z/TzvK9hTsj
#include <set>
#include <vector>
#include <iostream>
template<class T> class HappsAllocator {
public:
using value_type = T;
T* allocate(size_t count) {
size_t add = sizeof(T)*count;
std::cout << "allocate("<<add<<"/"<<(buf_.size()-current_)<<")\n";
if(current_+add > buf_.size()) throw std::bad_alloc{};
char* result = buf_.data()+current_;
current_ += add;
return reinterpret_cast<T*>(result);
}
void deallocate(T* p, size_t count) {
size_t del = sizeof(T)*count;
std::cout << "deallocate("<<del<<")\n";
if(del==current_ && p==reinterpret_cast<T*>(buf_.data())) {
std::cout << "...alles frei.\n";
current_ = 0;// alles wieder freigeben
}
}
HappsAllocator() : HappsAllocator{1024} {}
explicit HappsAllocator(size_t mx)
: buf_(mx, 0), current_{0} { }
private:
std::vector<char> buf_;
size_t current_;
};
int main() {
constexpr size_t ANZ = 1*1000*1000;
using Happs = HappsAllocator<int>;
try {
Happs happs(ANZ*sizeof(int)); // Allokator vorbereiten
std::vector<int,Happs> data(happs);
data.reserve(ANZ); // Speicher in einem Schwung holen
for(int val=0; val < (int)ANZ; ++val)
data.push_back(val);
} catch(std::bad_alloc &ex) {
std::cout << "Speicher alle.\n";
}
}
Godbolt Listing lst-0707-godb.cpp, https://godbolt.org/z/TzvK9hTsj:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/TzvK9hTsj
#include <set>
#include <vector>
#include <iostream>
template<class T> class HappsAllocator {
public:
using value_type = T;
T* allocate(size_t count) {
size_t add = sizeof(T)*count;
std::cout << "allocate("<<add<<"/"<<(buf_.size()-current_)<<")\n";
if(current_+add > buf_.size()) throw std::bad_alloc{};
char* result = buf_.data()+current_;
current_ += add;
return reinterpret_cast<T*>(result);
}
void deallocate(T* p, size_t count) {
size_t del = sizeof(T)*count;
std::cout << "deallocate("<<del<<")\n";
if(del==current_ && p==reinterpret_cast<T*>(buf_.data())) {
std::cout << "...alles frei.\n";
current_ = 0;// alles wieder freigeben
}
}
HappsAllocator() : HappsAllocator{1024} {}
explicit HappsAllocator(size_t mx)
: buf_(mx, 0), current_{0} { }
private:
std::vector<char> buf_;
size_t current_;
};
int main() {
constexpr size_t ANZ = 1*1000*1000;
using Happs = HappsAllocator<int>;
try {
Happs happs(ANZ*sizeof(int)); // Allokator vorbereiten
std::vector<int,Happs> data(happs);
data.reserve(ANZ); // Speicher in einem Schwung holen
for(int val=0; val < (int)ANZ; ++val)
data.push_back(val);
} catch(std::bad_alloc &ex) {
std::cout << "Speicher alle.\n";
}
}
Listing 24.11: Typaliase sind manchmal klarer als die konkreten Typen.
Book listing lst-0709-book.cpp:
// https://godbolt.org/z/c97qra3M7
#include <vector>
#include <map>
#include <iostream>
using std::cout; using std::ostream;
template<typename K, typename T>
ostream& operator<<(ostream& os, std::pair<const K,T> value) {
return os << '[' << value.first << ':' << value.second << ']';
}
int main() {
{
using Cont = std::vector<int>;
Cont cont{ 1, 2, 3, 4, 5, 6 };
Cont::size_type sz = cont.size();
cout << "size=" << sz << " content= ";
for(Cont::const_iterator it = cont.begin(); it != cont.end(); ++it)
cout << *it << ' ';
cout << '\n';
}
{
using Cont = std::map<int,char>;
Cont cont{ {1,'a'}, {2,'b'}, {3,'c'}, {4,'d'}, {5,'e'}, {6,'f'} };
Cont::size_type sz = cont.size();
cout << "size=" << sz << " content= ";
for(Cont::const_iterator it = cont.begin(); it != cont.end(); ++it)
cout << *it << ' ';
cout << '\n';
}
}
Godbolt Listing lst-0709-godb.cpp, https://godbolt.org/z/c97qra3M7:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/c97qra3M7
#include <vector>
#include <map>
#include <iostream>
using std::cout; using std::ostream;
template<typename K, typename T>
ostream& operator<<(ostream& os, std::pair<const K,T> value) {
return os << '[' << value.first << ':' << value.second << ']';
}
int main() {
{
using Cont = std::vector<int>;
Cont cont{ 1, 2, 3, 4, 5, 6 };
Cont::size_type sz = cont.size();
cout << "size=" << sz << " content= ";
for(Cont::const_iterator it = cont.begin(); it != cont.end(); ++it)
cout << *it << ' ';
cout << '\n';
}
{
using Cont = std::map<int,char>;
Cont cont{ {1,'a'}, {2,'b'}, {3,'c'}, {4,'d'}, {5,'e'}, {6,'f'} };
Cont::size_type sz = cont.size();
cout << "size=" << sz << " content= ";
for(Cont::const_iterator it = cont.begin(); it != cont.end(); ++it)
cout << *it << ' ';
cout << '\n';
}
}
Listing 24.12: Dies ist die Schablone für die Beispiellistings dieses Abschnitts zu vector.
Book listing lst-0710-book.cpp:
// https://godbolt.org/z/WK86eaz1x
#include <vector>
#include <iostream>
using std::vector; using std::cout;
template<typename T>
std::ostream& operator<<(std::ostream&os, const vector<T>& data) {
for(const auto &e : data) {
os << e << ' ';
}
return os;
}
int main() {h
// Beispielcode hier
}
Godbolt Listing lst-0710-godb.cpp, https://godbolt.org/z/WK86eaz1x:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/WK86eaz1x
#include <vector>
#include <iostream>
using std::vector; using std::cout;
template<typename T>
std::ostream& operator<<(std::ostream&os, const vector<T>& data) {
for(const auto &e : data) {
os << e << ' ';
}
return os;
}
int main() {h
// Beispielcode hier
}
Listing 24.13: Der Standardkonstruktor initialisiert einen vector leer.
Book listing lst-0711-book.cpp:
// https://godbolt.org/z/7zMP5fo7c
vector<int> dataA;
vector<int> dataB{};
vector<int> dataC = {}; // keine Zuweisung
cout << format("{} {} {}\n", dataA.size(), dataB.size(), dataC.size()); // 0 0 0
Godbolt Listing lst-0711-godb.cpp, https://godbolt.org/z/7zMP5fo7c:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/7zMP5fo7c
vector<int> dataA;
vector<int> dataB{};
vector<int> dataC = {}; // keine Zuweisung
cout << format("{} {} {}\n", dataA.size(), dataB.size(), dataC.size()); // 0 0 0
Listing 24.14: Sie kopieren einen »vector« mittels des Konstruktors oder implizit.
Book listing lst-0712-book.cpp:
// https://godbolt.org/z/cE6G1aErs
auto zaehle(vector<int> arg) { return arg.size(); }
// …
vector input{1,2,3}; // vector<int>
vector outputA(input); // Kopie
vector outputB = input; // auch Kopie, keine Zuweisung
cout << zaehle(input) << '\n'; // Aufruf per Copy-by-Value
Godbolt Listing lst-0712-godb.cpp, https://godbolt.org/z/cE6G1aErs:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/cE6G1aErs
auto zaehle(vector<int> arg) { return arg.size(); }
// …
vector input{1,2,3}; // vector<int>
vector outputA(input); // Kopie
vector outputB = input; // auch Kopie, keine Zuweisung
cout << zaehle(input) << '\n'; // Aufruf per Copy-by-Value
Listing 24.15: Bei Rückgabewerten kann der Compiler auch oft verschieben.
Book listing lst-0713-book.cpp:
// https://godbolt.org/z/EK4e7Trv3
#include <list>
#include <string>
#include <iterator> // make_move_iterator
using std::make_move_iterator; using std::string;
vector<int> erzeuge() { return vector<int>{8, 9, 10}; }
size_t zaehle(vector<int> d) { return d.size(); }
// …
vector input{1,2,3};
vector outputA(std::move(input)); // Verschiebung
vector outputB = std::move(input); // auch Verschiebung, keine Zuweisung
vector data = erzeuge(); // Return-Value-Optimization
cout << zaehle(input) << '\n'; // Aufruf per Copy-by-Value
// elementweise aus einem anderen Container verschieben
std::list<string> quelle{ "a", "a", "a", "BB", "CC", "DD", "b", "b" };
auto von = quelle.begin();
std::advance(von, 3); // 3 vorwärts, bei list aber langsam
auto bis = von;
std::advance(bis, 3); // noch mal 3 vorwärts
vector ziel(make_move_iterator(von), make_move_iterator(bis));
// quelle ist nun {"a", "a", "a", "", "", "", "b", "b"}, ziel ist nun {"BB", "CC", "DD"}
Godbolt Listing lst-0713-godb.cpp, https://godbolt.org/z/EK4e7Trv3:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/EK4e7Trv3
#include <list>
#include <string>
#include <iterator> // make_move_iterator
using std::make_move_iterator; using std::string;
vector<int> erzeuge() { return vector<int>{8, 9, 10}; }
size_t zaehle(vector<int> d) { return d.size(); }
// …
vector input{1,2,3};
vector outputA(std::move(input)); // Verschiebung
vector outputB = std::move(input); // auch Verschiebung, keine Zuweisung
vector data = erzeuge(); // Return-Value-Optimization
cout << zaehle(input) << '\n'; // Aufruf per Copy-by-Value
// elementweise aus einem anderen Container verschieben
std::list<string> quelle{ "a", "a", "a", "BB", "CC", "DD", "b", "b" };
auto von = quelle.begin();
std::advance(von, 3); // 3 vorwärts, bei list aber langsam
auto bis = von;
std::advance(bis, 3); // noch mal 3 vorwärts
vector ziel(make_move_iterator(von), make_move_iterator(bis));
// quelle ist nun {"a", "a", "a", "", "", "", "b", "b"}, ziel ist nun {"BB", "CC", "DD"}
Listing 24.16: Mit einer Initialisierungsliste befüllen Sie einen vector vorab. Achten Sie auf die korrekten Typen in der Liste.
Book listing lst-0714-book.cpp:
// https://godbolt.org/z/4T7fjxdPa
vector<int> prims{ 2,3,5,7,11 };
vector gerade{ 2,4,6,8,10 };
vector<int> soNicht{ 'a', 4.3, 8L }; // (ERR) "Narrowing" double nicht okay
vector<string> namen{ "sind", "nur" }; // konvertiert Argumente
vector schall{ "rauch", "qualm" }; // gefährlich: vector<const char[]>
vector nass{ "regen"s, "wasser"s }; // vector<string>
vector kalt{ "eis"sv, "pol"sv }; // vector<string_view>
Godbolt Listing lst-0714-godb.cpp, https://godbolt.org/z/4T7fjxdPa:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/4T7fjxdPa
vector<int> prims{ 2,3,5,7,11 };
vector gerade{ 2,4,6,8,10 };
vector<int> soNicht{ 'a', 4.3, 8L }; // (ERR) "Narrowing" double nicht okay
vector<string> namen{ "sind", "nur" }; // konvertiert Argumente
vector schall{ "rauch", "qualm" }; // gefährlich: vector<const char[]>
vector nass{ "regen"s, "wasser"s }; // vector<string>
vector kalt{ "eis"sv, "pol"sv }; // vector<string_view>
Listing 24.17: Kopieren Sie bei der Initialisierung Werte aus einem beliebigen anderen Container oder C-Array.
Book listing lst-0715-book.cpp:
// https://godbolt.org/z/foPadWsKs
#include <deque>
#include <ranges> // C++20
// …
std::deque in{1,2,33,34,35,99};
vector dreissig(in.begin()+2, in.begin()+5);
for(auto &e : dreissig) {
cout << e << ' ';
}
cout << '\n';
namespace vs = std::ranges::views; // C++20
auto v = in | vs::drop(2) | vs::take(3);
vector otuz(v.begin(), v.end());
vector trente(std::from_range, in); // C++23
Godbolt Listing lst-0715-godb.cpp, https://godbolt.org/z/foPadWsKs:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/foPadWsKs
#include <deque>
#include <ranges> // C++20
// …
std::deque in{1,2,33,34,35,99};
vector dreissig(in.begin()+2, in.begin()+5);
for(auto &e : dreissig) {
cout << e << ' ';
}
cout << '\n';
namespace vs = std::ranges::views; // C++20
auto v = in | vs::drop(2) | vs::take(3);
vector otuz(v.begin(), v.end());
vector trente(std::from_range, in); // C++23
Listing 24.18: Vorinitialisieren mit einer festen Anzahl von Werten gibt es (fast) nur bei »vector«.
Book listing lst-0716-book.cpp:
// https://godbolt.org/z/addobjfsK
vector<int> zeros(10); // 10 Nullen
vector<int> sechsen(10, 6); // 10 Sechsen
vector<int> zehn{10}; // (ERR) Achtung! Nur eine 10
vector<int> zehnSechs{10, 6}; // (ERR) Achtung! Zwei Elemente 10 und 6
Godbolt Listing lst-0716-godb.cpp, https://godbolt.org/z/addobjfsK:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/addobjfsK
vector<int> zeros(10); // 10 Nullen
vector<int> sechsen(10, 6); // 10 Sechsen
vector<int> zehn{10}; // (ERR) Achtung! Nur eine 10
vector<int> zehnSechs{10, 6}; // (ERR) Achtung! Zwei Elemente 10 und 6
Listing 24.19: »vector« können Sie zuweisen oder mit »assign« später reinitialisieren.
Book listing lst-0717-book.cpp:
// https://godbolt.org/z/Yb4jEdaKj
vector<int> von{ 2,3,4 };
vector<int> nach{};
nach = von; // Zuweisung mit operator=, nun beide gleich
vector<int> abfluss{};
abfluss = std::move(von); // Verschieben, nun ist 'von' leer
vector<int> v;
v.assign(4, 100); // v ist nun {100, 100, 100, 100}
v.assign(nach.begin(), nach.end()); // v ist nun {2,3,4}
int z[] = { 10, 20, 30, 40 };
v.assign(z+1, z+4); // v ist nun {20, 30, 40}
Godbolt Listing lst-0717-godb.cpp, https://godbolt.org/z/Yb4jEdaKj:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Yb4jEdaKj
vector<int> von{ 2,3,4 };
vector<int> nach{};
nach = von; // Zuweisung mit operator=, nun beide gleich
vector<int> abfluss{};
abfluss = std::move(von); // Verschieben, nun ist 'von' leer
vector<int> v;
v.assign(4, 100); // v ist nun {100, 100, 100, 100}
v.assign(nach.begin(), nach.end()); // v ist nun {2,3,4}
int z[] = { 10, 20, 30, 40 };
v.assign(z+1, z+4); // v ist nun {20, 30, 40}
Listing 24.20: Mit »begin«, »end« und deren Verwandten erhalten Sie Iteratoren.
Book listing lst-0718-book.cpp:
// https://godbolt.org/z/6ahzhdjva
vector vokale { 'A', 'e', 'i', 'o', 'u' };
const vector gerade { '0', '2', '4', '6', '8' };
auto it1 = vokale.begin(); // vector<char>::iterator
*it1 = 'a'; // '*it1' liefert 'char&' zurück
auto it2 = gerade.begin(); // vector<char>::const_iterator
auto it3 = vokale.cbegin(); // erzwingt const_iterator
*i2 = '9'; *i3 = 'x'; // (ERR) 'const char&' ist nicht veränderbar
for(auto it=vokale.cbegin()+1; it!=vokale.cend(); ++it)
{ cout << *it; } cout << '\n'; // Ausgabe: eiou
for(auto it=vokale.crbegin()+1; it!=vokale.crend(); ++it) // ++ trotz reverse!
{ cout << *it; } cout << '\n'; // Ausgabe: oiea
Godbolt Listing lst-0718-godb.cpp, https://godbolt.org/z/6ahzhdjva:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/6ahzhdjva
vector vokale { 'A', 'e', 'i', 'o', 'u' };
const vector gerade { '0', '2', '4', '6', '8' };
auto it1 = vokale.begin(); // vector<char>::iterator
*it1 = 'a'; // '*it1' liefert 'char&' zurück
auto it2 = gerade.begin(); // vector<char>::const_iterator
auto it3 = vokale.cbegin(); // erzwingt const_iterator
*i2 = '9'; *i3 = 'x'; // (ERR) 'const char&' ist nicht veränderbar
for(auto it=vokale.cbegin()+1; it!=vokale.cend(); ++it)
{ cout << *it; } cout << '\n'; // Ausgabe: eiou
for(auto it=vokale.crbegin()+1; it!=vokale.crend(); ++it) // ++ trotz reverse!
{ cout << *it; } cout << '\n'; // Ausgabe: oiea
Listing 24.21: Mit »vector«-Iteratoren können Sie wahlfrei rechnen.
Book listing lst-0719-book.cpp:
// https://godbolt.org/z/vMa8bPaob
#include <vector>
#include <iostream>
#include <algorithm> // ranges::sort
using std::vector; using std::cout;
double median(vector<int> daten) { // kopiert
std::ranges::sort(daten); // C++20, sonst std::sort()
auto it = daten.begin();
auto sz = daten.size();
if(sz==0) return 0; // Sonderfall
// Median ermitteln:
auto m = (it+sz/2); // ungefähr die Mitte
if(sz%2 != 0) { // ungerade Anzahl Elemente
return *m;
} else { // gerade Anzahl Elemente
return double(*m + *(m-1)) / 2;
}
}
int main() {
vector daten1 { 12, 22, 34, 10, 1, 99, 33 };
cout << median(daten1) << '\n'; // 22
vector daten2 { 30, 2, 80, 99, 31, 3 };
cout << median(daten2) << '\n'; // 30.5
}
Godbolt Listing lst-0719-godb.cpp, https://godbolt.org/z/vMa8bPaob:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/vMa8bPaob
#include <vector>
#include <iostream>
#include <algorithm> // ranges::sort
using std::vector; using std::cout;
double median(vector<int> daten) { // kopiert
std::ranges::sort(daten); // C++20, sonst std::sort()
auto it = daten.begin();
auto sz = daten.size();
if(sz==0) return 0; // Sonderfall
// Median ermitteln:
auto m = (it+sz/2); // ungefähr die Mitte
if(sz%2 != 0) { // ungerade Anzahl Elemente
return *m;
} else { // gerade Anzahl Elemente
return double(*m + *(m-1)) / 2;
}
}
int main() {
vector daten1 { 12, 22, 34, 10, 1, 99, 33 };
cout << median(daten1) << '\n'; // 22
vector daten2 { 30, 2, 80, 99, 31, 3 };
cout << median(daten2) << '\n'; // 30.5
}
Listing 24.22: Der Normalfall ist Zugriff mit »[]«, weil Sie die Grenzen schon woanders überprüfen.
Book listing lst-0720-book.cpp:
// https://godbolt.org/z/aW3McGofx
vector d{ 1, 2, 4, -1, 1, 2, -2 };
for(size_t idx=0; idx < d.size(); ) { // prüft vector-Grenze
cout << d[idx] << ' '; // zusätzliche Prüfung mit at nicht nötig
idx += d[idx]; // hier ebenso wenig
}
cout << '\n';
// Ausgabe: 1 2 -1 4 -2 1 2
Godbolt Listing lst-0720-godb.cpp, https://godbolt.org/z/aW3McGofx:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/aW3McGofx
vector d{ 1, 2, 4, -1, 1, 2, -2 };
for(size_t idx=0; idx < d.size(); ) { // prüft vector-Grenze
cout << d[idx] << ' '; // zusätzliche Prüfung mit at nicht nötig
idx += d[idx]; // hier ebenso wenig
}
cout << '\n';
// Ausgabe: 1 2 -1 4 -2 1 2
Listing 24.23: Konstanter Container liefert konstante Referenz zurück.
Book listing lst-0721-book.cpp:
// https://godbolt.org/z/jGx51caTj
#include <vector>
#include <iostream>
void printAndMore(const std::vector<int>& data) { // by-const-ref
std::cout << data[0] << std::endl;
data[0] = 666; // (ERR) geht nicht, weil 'const int&'
}
int main() {
std::vector zahlen {1,2,3};
printAndMore(zahlen);
}
Godbolt Listing lst-0721-godb.cpp, https://godbolt.org/z/jGx51caTj:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/jGx51caTj
#include <vector>
#include <iostream>
void printAndMore(const std::vector<int>& data) { // by-const-ref
std::cout << data[0] << std::endl;
data[0] = 666; // (ERR) geht nicht, weil 'const int&'
}
int main() {
std::vector zahlen {1,2,3};
printAndMore(zahlen);
}
Listing 24.24: insert verschiebt hier alle Elemente um eins nach hinten.
Book listing lst-0722-book.cpp:
// https://godbolt.org/z/YhYs3z5Ex
vector<string> autos{ "Diesel", "Benzin", "Super", "Gas" };
cout << autos[1] << '\n'; // Ausgabe: Benzin
autos.insert(autos.begin(), "Strom"); // verschiebt alles um eins nach hinten
cout << autos[1] << '\n'; // Ausgabe: Diesel
Godbolt Listing lst-0722-godb.cpp, https://godbolt.org/z/YhYs3z5Ex:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/YhYs3z5Ex
vector<string> autos{ "Diesel", "Benzin", "Super", "Gas" };
cout << autos[1] << '\n'; // Ausgabe: Benzin
autos.insert(autos.begin(), "Strom"); // verschiebt alles um eins nach hinten
cout << autos[1] << '\n'; // Ausgabe: Diesel
Listing 24.25: Verwenden Sie data() als Schnittstelle zu C.
Book listing lst-0723-book.cpp:
// https://godbolt.org/z/evse4x8zK
#include <vector>
#include <iostream>
#include <cstdio> // fopen, fclose, fwrite, fread, remove
using namespace std;
ostream& operator<<(ostream&os, const vector<int>&data) {
for(auto &e : data) os << e << ' '; return os;
}
static const char* FILENAME = "nums.dat";
int main() {
const vector nums{10,11,22,34};
{ // Schreiben
auto out = fopen(FILENAME, "wb"); // Datei mit C zum Schreiben öffnen
if(out==nullptr) {
cerr << "Fehler beim Oeffnen\n"; return -1;
}
auto ok = fwrite(nums.data(), sizeof(int), nums.size(), out);
if(ok!=nums.size()) {
cerr << "Fehler beim Schreiben\n"; return -1;
}
fclose(out); // In C muss man explizit schließen. Ehrlich.
}
vector<int> gelesen{};
{ // Lesen
auto in = fopen(FILENAME, "rb"); // Datei mit C zum Lesen öffnen
if(in==nullptr) {
cerr << "Fehler beim Oeffnen\n"; return -1;
}
const size_t sz = 4; // angenommen, wir wissen, wir lesen 4 Elemente …
gelesen.resize(sz); // Platz schaffen für zu lesende Daten
auto ok = fread(gelesen.data(), sizeof(int), sz, in);
if(ok!=sz) {
cerr << "Fehler beim Lesen\n"; return -1;
}
fclose(in);
}
{ // Vergleichen
cout << nums << '\n'; // 10 11 22 34
cout << gelesen << '\n'; // 10 11 22 34
}
if(remove(FILENAME) == -1) {
cerr << "Warning: Fehler beim Loeschen\n";
}
}
Godbolt Listing lst-0723-godb.cpp, https://godbolt.org/z/evse4x8zK:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/evse4x8zK
#include <vector>
#include <iostream>
#include <cstdio> // fopen, fclose, fwrite, fread, remove
using namespace std;
ostream& operator<<(ostream&os, const vector<int>&data) {
for(auto &e : data) os << e << ' '; return os;
}
static const char* FILENAME = "nums.dat";
int main() {
const vector nums{10,11,22,34};
{ // Schreiben
auto out = fopen(FILENAME, "wb"); // Datei mit C zum Schreiben öffnen
if(out==nullptr) {
cerr << "Fehler beim Oeffnen\n"; return -1;
}
auto ok = fwrite(nums.data(), sizeof(int), nums.size(), out);
if(ok!=nums.size()) {
cerr << "Fehler beim Schreiben\n"; return -1;
}
fclose(out); // In C muss man explizit schließen. Ehrlich.
}
vector<int> gelesen{};
{ // Lesen
auto in = fopen(FILENAME, "rb"); // Datei mit C zum Lesen öffnen
if(in==nullptr) {
cerr << "Fehler beim Oeffnen\n"; return -1;
}
const size_t sz = 4; // angenommen, wir wissen, wir lesen 4 Elemente …
gelesen.resize(sz); // Platz schaffen für zu lesende Daten
auto ok = fread(gelesen.data(), sizeof(int), sz, in);
if(ok!=sz) {
cerr << "Fehler beim Lesen\n"; return -1;
}
fclose(in);
}
{ // Vergleichen
cout << nums << '\n'; // 10 11 22 34
cout << gelesen << '\n'; // 10 11 22 34
}
if(remove(FILENAME) == -1) {
cerr << "Warning: Fehler beim Loeschen\n";
}
}
Listing 24.26: So verwenden Sie span.
Book listing lst-0728-book.cpp:
// https://godbolt.org/z/h7jf4KM1q
#include <vector>
#include <span>
#include <iostream>
using namespace std;
int sum(span<const int> bereich) { // C++20: span
int sum = 0;
for(auto e : bereich) { // algorithm wäre besser …
sum += e;
}
return sum;
}
int main() {
vector data {1,2,3,4,5};
cout << sum(data) << "\n"; // implizit Container zu span
auto [b, e, sz] = make_tuple(begin(data), end(data), size(data));
cout << sum(span{b, sz-1}) << "\n"; // 1..4 (Iter, size)
cout << sum(span{b+1, sz-1}) << "\n"; // 2..5 (Iter, size)
cout << sum(span{b, e-2}) << "\n"; // 1..3 (Iter, Iter)
cout << sum(span{b+1, e-1}) << "\n"; // 2..4 (Iter, Iter)
cout << sum(span{b+2, e }) << "\n"; // 3..5 (Iter, Iter)
return 0;
}
Godbolt Listing lst-0728-godb.cpp, https://godbolt.org/z/h7jf4KM1q:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/h7jf4KM1q
#include <vector>
#include <span>
#include <iostream>
using namespace std;
int sum(span<const int> bereich) { // C++20: span
int sum = 0;
for(auto e : bereich) { // algorithm wäre besser …
sum += e;
}
return sum;
}
int main() {
vector data {1,2,3,4,5};
cout << sum(data) << "\n"; // implizit Container zu span
auto [b, e, sz] = make_tuple(begin(data), end(data), size(data));
cout << sum(span{b, sz-1}) << "\n"; // 1..4 (Iter, size)
cout << sum(span{b+1, sz-1}) << "\n"; // 2..5 (Iter, size)
cout << sum(span{b, e-2}) << "\n"; // 1..3 (Iter, Iter)
cout << sum(span{b+1, e-1}) << "\n"; // 2..4 (Iter, Iter)
cout << sum(span{b+2, e }) << "\n"; // 3..5 (Iter, Iter)
return 0;
}
Listing 24.27: Dies sind span mit fester Größe.
Book listing lst-0731-book.cpp:
// https://godbolt.org/z/a3qqr1YPM
int car[5] {1,2,3,4,5};
span span_1 = car; // direkt aus einem C-Array
array arr {1,2,3,4,5};
span span_2 {arr}; // direkt aus einem std::array
vector vec {1,2,3,4,5};
span<int,3> span_3 {vec}; // mit 'Extent' aus einem std::vector
Godbolt Listing lst-0731-godb.cpp, https://godbolt.org/z/a3qqr1YPM:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/a3qqr1YPM
int car[5] {1,2,3,4,5};
span span_1 = car; // direkt aus einem C-Array
array arr {1,2,3,4,5};
span span_2 {arr}; // direkt aus einem std::array
vector vec {1,2,3,4,5};
span<int,3> span_3 {vec}; // mit 'Extent' aus einem std::vector
Listing 24.28: Durch eine »span« kann man auch schreiben.
Book listing lst-0733-book.cpp:
// https://godbolt.org/z/6Ez5GdozG
#include <vector>
#include <span>
#include <iostream>
using namespace std;
void inc(span<int> span) {
for(auto& e :span) { // Referenz
e += 1; // schreiben
}
}
int main() {
vector data {1,2,3,4,5};
span ganz{data}; // 1,2,3,4,5
inc(ganz.first(3)); // -> 2,3,4,4,5
inc(ganz.last(3)); // -> 2,3,5,5,6
inc(ganz.last(4).first(3)); // -> 2,4,6,6,6
inc(ganz.subspan(1,3)); // -> 2,5,7,7,6
for(auto i: ganz) cout << i << ' '; cout << '\n'; // Ausgabe: 2 5 7 7 6
return 0;
}
Godbolt Listing lst-0733-godb.cpp, https://godbolt.org/z/6Ez5GdozG:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/6Ez5GdozG
#include <vector>
#include <span>
#include <iostream>
using namespace std;
void inc(span<int> span) {
for(auto& e :span) { // Referenz
e += 1; // schreiben
}
}
int main() {
vector data {1,2,3,4,5};
span ganz{data}; // 1,2,3,4,5
inc(ganz.first(3)); // -> 2,3,4,4,5
inc(ganz.last(3)); // -> 2,3,5,5,6
inc(ganz.last(4).first(3)); // -> 2,4,6,6,6
inc(ganz.subspan(1,3)); // -> 2,5,7,7,6
for(auto i: ganz) cout << i << ' '; cout << '\n'; // Ausgabe: 2 5 7 7 6
return 0;
}
Listing 24.29: So funktioniert die in C++23 hinzugekommene »mdspan«.
Book listing lst-0734-book.cpp:
// https://godbolt.org/z/n8jn7v5vb
#include <mdspan>
#include <iostream>
#include <vector>
using namespace std;
int main() {
// 1D: 12 Elemente
vector v{1,2,3,4,5,6,7,8,9,10,11,12};
// 2D: als 2 Zeilen mit je 6 ints
auto ms2 = mdspan(v.data(), 2, 6);
// 3D: als Quader mit 2 Ebenen, 3 Reihen, 2 Spalten
auto ms3 = mdspan(v.data(), 2, 3, 2);
// via 2D-Ansicht schreiben
for (auto i = 0; i != ms2.extent(0); ++i)
for (auto j = 0; j != ms2.extent(1); ++j)
ms2[i, j] = i * 100 + j; // schreiben via mehrdimensionalen Index
// via 3D-Ansicht lesen
for (auto i = 0; i != ms3.extent(0); ++i) {
cout << "Ebene " << i << ":\n";
for (auto j = 0; j != ms3.extent(1); ++j) {
for (auto k = 0; k != ms3.extent(2); ++k)
cout << " " << ms3[i, j, k]; // lesen via mehrdimensionalen Index
cout << '\n';
}
}
// Ausgabe: Ebene 0: 0 1, 2 3, 4 5, Ebene 1: 100 101, 102 103, 104 105
}
Godbolt Listing lst-0734-godb.cpp, https://godbolt.org/z/n8jn7v5vb:
//#(compile) c++; compiler:gsnapshot; options:"-std=c++23"; libs:-
// https://godbolt.org/z/n8jn7v5vb
#include <mdspan>
#include <iostream>
#include <vector>
using namespace std;
int main() {
// 1D: 12 Elemente
vector v{1,2,3,4,5,6,7,8,9,10,11,12};
// 2D: als 2 Zeilen mit je 6 ints
auto ms2 = mdspan(v.data(), 2, 6);
// 3D: als Quader mit 2 Ebenen, 3 Reihen, 2 Spalten
auto ms3 = mdspan(v.data(), 2, 3, 2);
// via 2D-Ansicht schreiben
for (auto i = 0; i != ms2.extent(0); ++i)
for (auto j = 0; j != ms2.extent(1); ++j)
ms2[i, j] = i * 100 + j; // schreiben via mehrdimensionalen Index
// via 3D-Ansicht lesen
for (auto i = 0; i != ms3.extent(0); ++i) {
cout << "Ebene " << i << ":\n";
for (auto j = 0; j != ms3.extent(1); ++j) {
for (auto k = 0; k != ms3.extent(2); ++k)
cout << " " << ms3[i, j, k]; // lesen via mehrdimensionalen Index
cout << '\n';
}
}
// Ausgabe: Ebene 0: 0 1, 2 3, 4 5, Ebene 1: 100 101, 102 103, 104 105
}
Listing 24.30: Typischerweise fügen Sie am Ende bei vector an.
Book listing lst-0735-book.cpp:
// https://godbolt.org/z/P6MrKfaj9
#include <vector>
#include <string>
struct Praesident {
std::string name_; int jahr_;
Praesident(std::string name, int jahr) // name ist by Value
: name_{std::move(name)}, jahr_{jahr} // move spart hier eine weitere Kopie
{ }
};
int main() {
using namespace std; // Stringliterale ermöglichen
vector<Praesident> praesidenten{};
praesidenten.emplace_back("Heuss"s, 1949);
praesidenten.emplace_back("Luebke"s, 1959);
praesidenten.emplace_back("Heinemann"s, 1969);
// …
vector<int> v{};
v.reserve(100);
for(int idx = 0; idx < 100; ++idx)
v.push_back(idx);
// …
}
Godbolt Listing lst-0735-godb.cpp, https://godbolt.org/z/P6MrKfaj9:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/P6MrKfaj9
#include <vector>
#include <string>
struct Praesident {
std::string name_; int jahr_;
Praesident(std::string name, int jahr) // name ist by Value
: name_{std::move(name)}, jahr_{jahr} // move spart hier eine weitere Kopie
{ }
};
int main() {
using namespace std; // Stringliterale ermöglichen
vector<Praesident> praesidenten{};
praesidenten.emplace_back("Heuss"s, 1949);
praesidenten.emplace_back("Luebke"s, 1959);
praesidenten.emplace_back("Heinemann"s, 1969);
// …
vector<int> v{};
v.reserve(100);
for(int idx = 0; idx < 100; ++idx)
v.push_back(idx);
// …
}
GodboltId:6836bdczd
Book listing lst-0738-book.cpp:
// https://godbolt.org/z/6836bdczd
std::vector v{ 1, 2, 3, 4, 5, 6 };
for(auto it=v.begin(); it!=v.end(); ++it) {
it = v.erase(it);
}
// Hier ist v: { 2, 4, 6 }
Godbolt Listing lst-0738-godb.cpp, https://godbolt.org/z/6836bdczd:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/6836bdczd
std::vector v{ 1, 2, 3, 4, 5, 6 };
for(auto it=v.begin(); it!=v.end(); ++it) {
it = v.erase(it);
}
// Hier ist v: { 2, 4, 6 }
Listing 24.31: erase mit zwei Parametern löscht einen ganzen Bereich.
Book listing lst-0739-book.cpp:
// https://godbolt.org/z/fe8bev9Y9
std::vector v{ 1, 2, 3, 4, 5, 6 };
v.erase(v.begin()+2, v.begin()+5); // v ist nun {1, 6}
v.erase(v.begin(), v.end()); // löscht den Rest
Godbolt Listing lst-0739-godb.cpp, https://godbolt.org/z/fe8bev9Y9:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/fe8bev9Y9
std::vector v{ 1, 2, 3, 4, 5, 6 };
v.erase(v.begin()+2, v.begin()+5); // v ist nun {1, 6}
v.erase(v.begin(), v.end()); // löscht den Rest
Listing 24.32: Operationen rund um Größe und Kapazität von »vector«.
Book listing lst-0741-book.cpp:
// https://godbolt.org/z/xYsherrjs
#include <vector>
#include <iostream>
#include <format> // C++20
using namespace std;
ostream& operator<<(ostream&os, const vector<int> &vec) {
for(auto &elem : vec) { os << elem << ' '; } return os;
}
int main() {
vector<int> data {}; // erzeugt einen leeren vector
data.reserve(3); // Platz für 3 Elemente
cout << format("{}/{}\n", data.size(), data.capacity()); // 0/3
data.push_back(111); // ein Element hinzufügen
data.resize(3); // Größe verändern; hier fügt es neue Elemente an
data.push_back(999); // noch ein Element hinzufügen
cout << format("{}/{}\n", data.size(), data.capacity()); // 4/6
cout << data << '\n'; // 111, 0, 0, 999
data.push_back(333); // noch ein Element anfügen
cout << data << '\n'; // 111, 0, 0, 999, 333
data.reserve(1); // nichts passiert, denn capacity() > 1
data.resize(3); // schrumpfen; Elemente werden entfernt
cout << data << '\n'; // 111, 0, 0
cout << format("{}/{}\n", data.size(), data.capacity()); // 3/6
data.resize(6, 44); // noch mal vergrößern, mit 44en auffüllen
cout << data << '\n'; // 111, 0, 0, 44, 44, 44
}
Godbolt Listing lst-0741-godb.cpp, https://godbolt.org/z/xYsherrjs:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/xYsherrjs
#include <vector>
#include <iostream>
#include <format> // C++20
using namespace std;
ostream& operator<<(ostream&os, const vector<int> &vec) {
for(auto &elem : vec) { os << elem << ' '; } return os;
}
int main() {
vector<int> data {}; // erzeugt einen leeren vector
data.reserve(3); // Platz für 3 Elemente
cout << format("{}/{}\n", data.size(), data.capacity()); // 0/3
data.push_back(111); // ein Element hinzufügen
data.resize(3); // Größe verändern; hier fügt es neue Elemente an
data.push_back(999); // noch ein Element hinzufügen
cout << format("{}/{}\n", data.size(), data.capacity()); // 4/6
cout << data << '\n'; // 111, 0, 0, 999
data.push_back(333); // noch ein Element anfügen
cout << data << '\n'; // 111, 0, 0, 999, 333
data.reserve(1); // nichts passiert, denn capacity() > 1
data.resize(3); // schrumpfen; Elemente werden entfernt
cout << data << '\n'; // 111, 0, 0
cout << format("{}/{}\n", data.size(), data.capacity()); // 3/6
data.resize(6, 44); // noch mal vergrößern, mit 44en auffüllen
cout << data << '\n'; // 111, 0, 0, 44, 44, 44
}
GodboltId:Y1W8WfxYn
Book listing lst-0742-book.cpp:
// https://godbolt.org/z/Y1W8WfxYn
#include <array>
void berechne(const std::array<int,4>& data) { /* ... */ }
void berechne(const std::array<int,5>& data) { /* ... */ }
Godbolt Listing lst-0742-godb.cpp, https://godbolt.org/z/Y1W8WfxYn:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Y1W8WfxYn
#include <array>
void berechne(const std::array<int,4>& data) { /* ... */ }
void berechne(const std::array<int,5>& data) { /* ... */ }
Listing 24.33: Unterschiedliche »arrays« als Parameter benötigen Templateprogrammierung.
Book listing lst-0743-book.cpp:
// https://godbolt.org/z/nqbKT9GEa
#include <array>
#include <numeric> // accumulate
#include <iostream>
template<size_t SZ>
int sumSz(const std::array<int,SZ>& data) {
int result = 0;
for(auto i=0uz; i<SZ; ++i) // uz ist das Suffix für size_t seit C++23
result += data[i];
return result;
}
template<typename Elem, size_t SZ>
Elem sumElem(const std::array<Elem,SZ>& data) {
Elem result {0};
for(auto i=0uz; i<SZ; ++i)
result += data[i];
return result;
}
// C++20-Concept input_iterator, sonst typename
template<std::input_iterator It>
int sumIt(It begin, It end) {
return std::accumulate(begin, end, 0);
}
int sumAuto(std::input_iterator auto begin, std::input_iterator auto end) {
return std::accumulate(begin, end, 0);
}
// abgekürztes funktionstemplate mit auto
int main() {
using namespace std;
array<int,4> a4 { 1, 2, 5, 8 };
cout << sumSz<4>(a4) << '\n'; // Ausgabe: 16
array<int,5> a5 { 1, -5, 3, 7, 2 };
cout << sumElem(a5) << '\n'; // Ausgabe: 8
array<int,6> a6 { 1,2,3, 4,5,6 };
cout << sumIt(a6.begin(), a6.end()) << '\n'; // Ausgabe: 21
array a7 { 1,2,3, 4,5,6, 7 }; // array<int,7>
cout << sumIt(a7.begin(), a7.end()) << '\n'; // Ausgabe: 28
cout << sumAuto(a7.begin(), a7.end()) << '\n'; // Ausgabe: 28
}
Godbolt Listing lst-0743-godb.cpp, https://godbolt.org/z/nqbKT9GEa:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/nqbKT9GEa
#include <array>
#include <numeric> // accumulate
#include <iostream>
template<size_t SZ>
int sumSz(const std::array<int,SZ>& data) {
int result = 0;
for(auto i=0uz; i<SZ; ++i) // uz ist das Suffix für size_t seit C++23
result += data[i];
return result;
}
template<typename Elem, size_t SZ>
Elem sumElem(const std::array<Elem,SZ>& data) {
Elem result {0};
for(auto i=0uz; i<SZ; ++i)
result += data[i];
return result;
}
// C++20-Concept input_iterator, sonst typename
template<std::input_iterator It>
int sumIt(It begin, It end) {
return std::accumulate(begin, end, 0);
}
int sumAuto(std::input_iterator auto begin, std::input_iterator auto end) {
return std::accumulate(begin, end, 0);
}
// abgekürztes funktionstemplate mit auto
int main() {
using namespace std;
array<int,4> a4 { 1, 2, 5, 8 };
cout << sumSz<4>(a4) << '\n'; // Ausgabe: 16
array<int,5> a5 { 1, -5, 3, 7, 2 };
cout << sumElem(a5) << '\n'; // Ausgabe: 8
array<int,6> a6 { 1,2,3, 4,5,6 };
cout << sumIt(a6.begin(), a6.end()) << '\n'; // Ausgabe: 21
array a7 { 1,2,3, 4,5,6, 7 }; // array<int,7>
cout << sumIt(a7.begin(), a7.end()) << '\n'; // Ausgabe: 28
cout << sumAuto(a7.begin(), a7.end()) << '\n'; // Ausgabe: 28
}
Listing 24.34: Schablone für die Beispiellistings dieses Abschnitts zu »array«
Book listing lst-0744-book.cpp:
// https://godbolt.org/z/PrM4fGcWo
#include <array>
#include <iostream>
using std::array; using std::cout;
template<typename Elem, size_t SZ>
std::ostream& operator<<(std::ostream&os, const array<Elem,SZ>&data) {
for(auto &e : data) {
os << e << ' ';
}
return os;
}
int main() {
// Beispielcode hier
}
Godbolt Listing lst-0744-godb.cpp, https://godbolt.org/z/PrM4fGcWo:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/PrM4fGcWo
#include <array>
#include <iostream>
using std::array; using std::cout;
template<typename Elem, size_t SZ>
std::ostream& operator<<(std::ostream&os, const array<Elem,SZ>&data) {
for(auto &e : data) {
os << e << ' ';
}
return os;
}
int main() {
// Beispielcode hier
}
Listing 24.36: »array« unterstützt »get« von »tuple«.
Book listing lst-0745-book.cpp:
// https://godbolt.org/z/KrbTrx1aG
array<int,5> data{ 10, 11, 12, 13, 14};
cout << std::get<2>(data) << '\n'; // 12
Godbolt Listing lst-0745-godb.cpp, https://godbolt.org/z/KrbTrx1aG:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/KrbTrx1aG
array<int,5> data{ 10, 11, 12, 13, 14};
cout << std::get<2>(data) << '\n'; // 12
Listing 24.37: Ein Array unterstützt strukturiertes Binden.
Book listing lst-0746-book.cpp:
// https://godbolt.org/z/h6nrPYWfM
#include <array>
#include <iostream>
int main() {
std::array ports { 80, 443 }; // array<int>
auto [ http, https ] = ports; // deklariert Variablen und bindet sie
std::cout << http << " " << https << "\n";
auto const& [ rhttp, rhttps ] = ports; // Referenz und const sind möglich
std::cout << rhttp << " " << rhttps << "\n";
}
Godbolt Listing lst-0746-godb.cpp, https://godbolt.org/z/h6nrPYWfM:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/h6nrPYWfM
#include <array>
#include <iostream>
int main() {
std::array ports { 80, 443 }; // array<int>
auto [ http, https ] = ports; // deklariert Variablen und bindet sie
std::cout << http << " " << https << "\n";
auto const& [ rhttp, rhttps ] = ports; // Referenz und const sind möglich
std::cout << rhttp << " " << rhttps << "\n";
}
Listing 24.38: Arrays können Sie lexikografisch vergleichen.
Book listing lst-0747-book.cpp:
// https://godbolt.org/z/n16WYf58h
template<typename E, size_t SZ>
void alle(const array<int,4>& a, const array<int,4>& b) { // absichtlich array&
// als Argumente
cout << "{"<<a<<"} verglichen mit {"<<b<<"} ist "
<< (a < b ? "<, " : "")
<< (a <= b ? "<=, " : "")
<< (a > b ? ">, " : "")
<< (a >= b ? ">=, " : "")
<< (a == b ? "==, " : "")
<< (a != b ? "!=, " : "")
<< '\n';
}
int main() {
array a{10,10,10,10};
array b{20, 5, 5, 5};
array c{10,10,5,21};
array d{10,10,10,10};
cout << (a < b ? "kleiner\n" : "nicht kleiner\n"); // "kleiner", weil 10 < 20
cout << (a < c ? "kleiner\n" : "nicht kleiner\n"); // "nicht …", weil nicht 10 < 5
cout << (a == d ? "gleich\n" : "nicht gleich\n"); // "gleich", weil alles 10
for(auto &x : {a,b,c}) {
for(auto &y : {a,b,c}) {
alle(x,y);
}
}
}
Godbolt Listing lst-0747-godb.cpp, https://godbolt.org/z/n16WYf58h:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/n16WYf58h
template<typename E, size_t SZ>
void alle(const array<int,4>& a, const array<int,4>& b) { // absichtlich array&
// als Argumente
cout << "{"<<a<<"} verglichen mit {"<<b<<"} ist "
<< (a < b ? "<, " : "")
<< (a <= b ? "<=, " : "")
<< (a > b ? ">, " : "")
<< (a >= b ? ">=, " : "")
<< (a == b ? "==, " : "")
<< (a != b ? "!=, " : "")
<< '\n';
}
int main() {
array a{10,10,10,10};
array b{20, 5, 5, 5};
array c{10,10,5,21};
array d{10,10,10,10};
cout << (a < b ? "kleiner\n" : "nicht kleiner\n"); // "kleiner", weil 10 < 20
cout << (a < c ? "kleiner\n" : "nicht kleiner\n"); // "nicht …", weil nicht 10 < 5
cout << (a == d ? "gleich\n" : "nicht gleich\n"); // "gleich", weil alles 10
for(auto &x : {a,b,c}) {
for(auto &y : {a,b,c}) {
alle(x,y);
}
}
}
Listing 24.39: Wir entfernen paarweise vorne und hinten und vergleichen.
Book listing lst-0748-book.cpp:
// https://godbolt.org/z/rc1f3Yd9r
#include <deque>
#include <iostream>
#include <string>
#include <cctype> // toupper
#include <iomanip> // boolalpha
using namespace std;
bool isPalindrome(string_view word) {
// von beiden Enden gleichzeitig prüfen
deque<char> deq{};
for(char ch : word) {
deq.push_back(toupper(ch)); // Großbuchstaben
}
auto ok = true;
while(deq.size()>1 && ok) {
if(deq.front() != deq.back()) {
ok = false;
}
deq.pop_front(); // Hallo deque!
deq.pop_back();
}
return ok;
}
int main() {
cout << boolalpha; // Drucke 'true' und 'false' statt '1' und '0'
cout << isPalindrome("Abrakadabra") << '\n'; // false
cout << isPalindrome("Kajak") << '\n'; // true
cout << isPalindrome("Lagerregal") << '\n'; // true
cout << isPalindrome("Reliefpfeiler") << '\n'; // true
cout << isPalindrome("Rentner") << '\n'; // true
cout << isPalindrome("") << '\n'; // true
}
Godbolt Listing lst-0748-godb.cpp, https://godbolt.org/z/rc1f3Yd9r:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/rc1f3Yd9r
#include <deque>
#include <iostream>
#include <string>
#include <cctype> // toupper
#include <iomanip> // boolalpha
using namespace std;
bool isPalindrome(string_view word) {
// von beiden Enden gleichzeitig prüfen
deque<char> deq{};
for(char ch : word) {
deq.push_back(toupper(ch)); // Großbuchstaben
}
auto ok = true;
while(deq.size()>1 && ok) {
if(deq.front() != deq.back()) {
ok = false;
}
deq.pop_front(); // Hallo deque!
deq.pop_back();
}
return ok;
}
int main() {
cout << boolalpha; // Drucke 'true' und 'false' statt '1' und '0'
cout << isPalindrome("Abrakadabra") << '\n'; // false
cout << isPalindrome("Kajak") << '\n'; // true
cout << isPalindrome("Lagerregal") << '\n'; // true
cout << isPalindrome("Reliefpfeiler") << '\n'; // true
cout << isPalindrome("Rentner") << '\n'; // true
cout << isPalindrome("") << '\n'; // true
}
Listing 24.40: Was die »deque« so alles kann!
Book listing lst-0750-book.cpp:
// https://godbolt.org/z/7P1Ef7jj4
#include <deque>
#include <iostream>
#include <iterator> // ostream_iterator
#include <algorithm> // copy
using namespace std;
ostream& operator<<=(ostream& os, int val) { return os<<val<<'\n'; }
int main() {
deque d{ 4, 6 }; // deque<int> mit Elementen erzeugen
// Einfügen
d.push_front(3); // am Kopf: effizient
d.insert(d.begin()+2, 5); // mittendrin: langsam
d.push_back(7); // am Ende: effizient
// Zugriff
cout <<= d.front(); // vom Kopf: effizient
cout <<= d[3]; // mittendrin: effizient
cout <<= d.back(); // vom Ende: effizient
// Größe
cout <<= d.size(); // Größe lesen
d.resize(4); // Größe kappen (oder erweitern)
// Iteratoren
copy(d.begin(), d.end(), ostream_iterator<int>(cout, " "));
cout << '\n'; // Ausgabe: 3 4 5 6
// Entfernen
d.pop_front(); // am Kopf: effizient
d.erase(d.begin()+1); // mittendrin: langsam
d.pop_back(); // am Ende: effizient
d.clear(); // leeren
}
Godbolt Listing lst-0750-godb.cpp, https://godbolt.org/z/7P1Ef7jj4:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/7P1Ef7jj4
#include <deque>
#include <iostream>
#include <iterator> // ostream_iterator
#include <algorithm> // copy
using namespace std;
ostream& operator<<=(ostream& os, int val) { return os<<val<<'\n'; }
int main() {
deque d{ 4, 6 }; // deque<int> mit Elementen erzeugen
// Einfügen
d.push_front(3); // am Kopf: effizient
d.insert(d.begin()+2, 5); // mittendrin: langsam
d.push_back(7); // am Ende: effizient
// Zugriff
cout <<= d.front(); // vom Kopf: effizient
cout <<= d[3]; // mittendrin: effizient
cout <<= d.back(); // vom Ende: effizient
// Größe
cout <<= d.size(); // Größe lesen
d.resize(4); // Größe kappen (oder erweitern)
// Iteratoren
copy(d.begin(), d.end(), ostream_iterator<int>(cout, " "));
cout << '\n'; // Ausgabe: 3 4 5 6
// Entfernen
d.pop_front(); // am Kopf: effizient
d.erase(d.begin()+1); // mittendrin: langsam
d.pop_back(); // am Ende: effizient
d.clear(); // leeren
}
Listing 24.41: »splice« ist die Spezialität von »list« und verbindet zwei Listen effizient.
Book listing lst-0751-book.cpp:
// https://godbolt.org/z/so5Gebb4M
#include <list>
#include <iostream>
using std::list; using std::cout; using std::ostream;
ostream& operator<<=(ostream&os, const list<int> &data)
{ for(auto &e:data) os<<e<<' '; return os<<'\n'; }
int main() {
list numa { 1, 3, 5, 7, 9 };
list numb { 2, 4, 6, 8 };
auto wo = numa.end();
numa.splice(wo, numb); // transferieren in O(1)
cout <<= numa; // Ausgabe: 1 3 5 7 9 2 4 6 8
cout <<= numb; // Ausgabe: (keine)
numa.sort(); // sort als Methode, nicht aus <algorithm>
cout <<= numa; // Ausgabe: 1 2 3 4 5 6 7 8 9
}
Godbolt Listing lst-0751-godb.cpp, https://godbolt.org/z/so5Gebb4M:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/so5Gebb4M
#include <list>
#include <iostream>
using std::list; using std::cout; using std::ostream;
ostream& operator<<=(ostream&os, const list<int> &data)
{ for(auto &e:data) os<<e<<' '; return os<<'\n'; }
int main() {
list numa { 1, 3, 5, 7, 9 };
list numb { 2, 4, 6, 8 };
auto wo = numa.end();
numa.splice(wo, numb); // transferieren in O(1)
cout <<= numa; // Ausgabe: 1 3 5 7 9 2 4 6 8
cout <<= numb; // Ausgabe: (keine)
numa.sort(); // sort als Methode, nicht aus <algorithm>
cout <<= numa; // Ausgabe: 1 2 3 4 5 6 7 8 9
}
Listing 24.42: »before_begin« können Sie als Argument für »insert_after« nehmen.
Book listing lst-0752-book.cpp:
// https://godbolt.org/z/9b9fY4Mve
#include <iostream>
#include <forward_list>
int main() {
std::forward_list mylist = {20, 30, 40, 50};
mylist.insert_after(mylist.before_begin(), 11 );
for (int& x: mylist) std::cout << ' ' << x; // Ausgabe: 11 20 30 40 50
std::cout << '\n';
}
Godbolt Listing lst-0752-godb.cpp, https://godbolt.org/z/9b9fY4Mve:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/9b9fY4Mve
#include <iostream>
#include <forward_list>
int main() {
std::forward_list mylist = {20, 30, 40, 50};
mylist.insert_after(mylist.before_begin(), 11 );
for (int& x: mylist) std::cout << ' ' << x; // Ausgabe: 11 20 30 40 50
std::cout << '\n';
}
Listing 24.43: »erase_after« kann einen Bereich von Elementen löschen.
Book listing lst-0753-book.cpp:
// https://godbolt.org/z/ajn3haEcY
#include <forward_list>
#include <iostream>
#include <iterator> // next
using std::cout; using std::forward_list; using std::ostream;
ostream& operator<<=(ostream&os, const forward_list<int> &data)
{ for(auto &e:data) os<<e<<' '; return os<<'\n'; }
int main() {
forward_list zahlen {40, 50, 60, 70};
cout <<= zahlen; // Ausgabe: 40 50 60 70
zahlen.insert_after(zahlen.before_begin(), {10, 20, 30});
cout <<= zahlen; // Ausgabe: 10 20 30 40 50 60 70
auto wo = std::next(zahlen.begin(), 2); // zwei Elemente weiter
auto bis = std::next(wo, 3); // drei Elemente nach wo
zahlen.erase_after(wo, bis);
cout <<= zahlen; // Ausgabe: 10 20 30 60 70
}
Godbolt Listing lst-0753-godb.cpp, https://godbolt.org/z/ajn3haEcY:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/ajn3haEcY
#include <forward_list>
#include <iostream>
#include <iterator> // next
using std::cout; using std::forward_list; using std::ostream;
ostream& operator<<=(ostream&os, const forward_list<int> &data)
{ for(auto &e:data) os<<e<<' '; return os<<'\n'; }
int main() {
forward_list zahlen {40, 50, 60, 70};
cout <<= zahlen; // Ausgabe: 40 50 60 70
zahlen.insert_after(zahlen.before_begin(), {10, 20, 30});
cout <<= zahlen; // Ausgabe: 10 20 30 40 50 60 70
auto wo = std::next(zahlen.begin(), 2); // zwei Elemente weiter
auto bis = std::next(wo, 3); // drei Elemente nach wo
zahlen.erase_after(wo, bis);
cout <<= zahlen; // Ausgabe: 10 20 30 60 70
}
Listing 24.44: »splice_after« kann sehr effizient Listen zusammenfügen.
Book listing lst-0754-book.cpp:
// https://godbolt.org/z/Ka47W5Wjh
#include <forward_list>
#include <iostream>
using std::cout; using std::forward_list; using std::ostream;
ostream& operator<<=(ostream&os, const forward_list<int> &data)
{ for(auto &e:data) os<<e<<' '; return os<<'\n'; }
int main() {
{
forward_list fw1 {10, 20, 30, 40};
forward_list fw2 {5, 6, 7, 8};
fw1.splice_after(fw1.begin(), fw2); // transferiert alles
cout <<= fw1; // Ausgabe: 10 5 6 7 8 20 30 40
cout <<= fw2; // Ausgabe:
}
{
forward_list fw1 {10, 20, 30, 40};
forward_list fw2 {5, 6, 7, 8};
// ein Element übrig:
fw1.splice_after(fw1.begin(), fw2,fw2.begin(),fw2.end());
cout <<= fw1; // Ausgabe: 10 6 7 8 20 30 40
cout <<= fw2; // Ausgabe: 5
}
}
Godbolt Listing lst-0754-godb.cpp, https://godbolt.org/z/Ka47W5Wjh:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Ka47W5Wjh
#include <forward_list>
#include <iostream>
using std::cout; using std::forward_list; using std::ostream;
ostream& operator<<=(ostream&os, const forward_list<int> &data)
{ for(auto &e:data) os<<e<<' '; return os<<'\n'; }
int main() {
{
forward_list fw1 {10, 20, 30, 40};
forward_list fw2 {5, 6, 7, 8};
fw1.splice_after(fw1.begin(), fw2); // transferiert alles
cout <<= fw1; // Ausgabe: 10 5 6 7 8 20 30 40
cout <<= fw2; // Ausgabe:
}
{
forward_list fw1 {10, 20, 30, 40};
forward_list fw2 {5, 6, 7, 8};
// ein Element übrig:
fw1.splice_after(fw1.begin(), fw2,fw2.begin(),fw2.end());
cout <<= fw1; // Ausgabe: 10 6 7 8 20 30 40
cout <<= fw2; // Ausgabe: 5
}
}
Listing 24.45: Dies ist die Schablone für die Beispiellistings dieses Abschnitts zu »set«.
Book listing lst-0755-book.cpp:
// https://godbolt.org/z/h51oT7r3h
#include <set>
#include <iostream>
using std::set; using std::cout;
template<typename Elem, typename Comp>
std::ostream& operator<<=(std::ostream&os, const set<Elem,Comp>&data) {
for(auto &e : data) {
os << e << ' ';
}
return os << '\n'; // '<<=' statt '<<' für Zeilenumbruch
}
int main() {
// Beispielcode hier
}
Godbolt Listing lst-0755-godb.cpp, https://godbolt.org/z/h51oT7r3h:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/h51oT7r3h
#include <set>
#include <iostream>
using std::set; using std::cout;
template<typename Elem, typename Comp>
std::ostream& operator<<=(std::ostream&os, const set<Elem,Comp>&data) {
for(auto &e : data) {
os << e << ' ';
}
return os << '\n'; // '<<=' statt '<<' für Zeilenumbruch
}
int main() {
// Beispielcode hier
}
Listing 24.46: Wenn Sie die Vergleichsoperation falsch definieren, funktioniert »set« nicht mehr.
Book listing lst-0757-book.cpp:
// https://godbolt.org/z/GbPsraKxa
using std::cout; using std::ostream; using std::set;
auto vergl = [](auto e, auto f) { return e <= f; }; // (ERR) ungültig definiert!
std::set<int,decltype(vergl)> data(vergl);
data.insert({ 9,5,7,2,3,6,8 });
cout <<= data; // Ausgabe mit Glück: 2 3 5 6 7 8 9
auto wo = data.find(7);
if(wo != data.end()) {
cout << "hab es: " << *wo << '\n';
} else {
cout << "weg isses!" << '\n'; // wahrscheinlich landen Sie hier
}
Godbolt Listing lst-0757-godb.cpp, https://godbolt.org/z/GbPsraKxa:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/GbPsraKxa
using std::cout; using std::ostream; using std::set;
auto vergl = [](auto e, auto f) { return e <= f; }; // (ERR) ungültig definiert!
std::set<int,decltype(vergl)> data(vergl);
data.insert({ 9,5,7,2,3,6,8 });
cout <<= data; // Ausgabe mit Glück: 2 3 5 6 7 8 9
auto wo = data.find(7);
if(wo != data.end()) {
cout << "hab es: " << *wo << '\n';
} else {
cout << "weg isses!" << '\n'; // wahrscheinlich landen Sie hier
}
Listing 24.47: Die Vergleichsoperation darf Elemente zusammenfassen.
Book listing lst-0758-book.cpp:
// https://godbolt.org/z/MeGnEez15
auto vergl = [](auto e, auto f) {return e/10<f/10;}; // zusammenfassen ist okay
std::set<int,decltype(vergl)> data(vergl);
data.insert({ 14,23,56,71 });
cout <<= data; // Ausgabe: 14 23 56 71
auto wo = data.find(29); // 29 findet nun auch die 23
if(wo != data.end()) {
cout << "hab es: " << *wo << '\n'; // Ausgabe: hab es: 23
}
data.insert(79); // nichts passiert, denn 71 ist schon drin
cout <<= data; // Ausgabe: 14 23 56 71
Godbolt Listing lst-0758-godb.cpp, https://godbolt.org/z/MeGnEez15:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/MeGnEez15
auto vergl = [](auto e, auto f) {return e/10<f/10;}; // zusammenfassen ist okay
std::set<int,decltype(vergl)> data(vergl);
data.insert({ 14,23,56,71 });
cout <<= data; // Ausgabe: 14 23 56 71
auto wo = data.find(29); // 29 findet nun auch die 23
if(wo != data.end()) {
cout << "hab es: " << *wo << '\n'; // Ausgabe: hab es: 23
}
data.insert(79); // nichts passiert, denn 71 ist schon drin
cout <<= data; // Ausgabe: 14 23 56 71
Listing 24.48: Ein eigener Spaceship-Operator für die »set«-Kompatibilität
Book listing lst-0759-book.cpp:
// https://godbolt.org/z/a3cnTn3zz
#include <iostream>
#include <set>
#include <string>
struct Dwarf {
std::string name;
int height;
auto operator<=>(const Dwarf& other) const {
return height <=> other.height;
}
};
int main() {
std::set<Dwarf> dwarves {
{"Thorin", 140}, {"Balin", 136}, {"Kili", 138},
{"Dwalin", 139}, {"Oin", 135}, {"Gloin", 137},
};
for(auto &d: dwarves) {
std::cout << d.name << ' ';
} // Ausgabe: Oin Balin Kili Gloin Dwalin Thorin
}
Godbolt Listing lst-0759-godb.cpp, https://godbolt.org/z/a3cnTn3zz:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/a3cnTn3zz
#include <iostream>
#include <set>
#include <string>
struct Dwarf {
std::string name;
int height;
auto operator<=>(const Dwarf& other) const {
return height <=> other.height;
}
};
int main() {
std::set<Dwarf> dwarves {
{"Thorin", 140}, {"Balin", 136}, {"Kili", 138},
{"Dwalin", 139}, {"Oin", 135}, {"Gloin", 137},
};
for(auto &d: dwarves) {
std::cout << d.name << ' ';
} // Ausgabe: Oin Balin Kili Gloin Dwalin Thorin
}
Listing 24.49: Es gibt verschiedene Möglichkeiten, einen Comparator anzugeben.
Book listing lst-0761-book.cpp:
// https://godbolt.org/z/1Eoh9aoas
#include <set>
#include <functional> // function
using std::set; using std::function; using std::initializer_list;
bool fcompZehner(int a, int b) { return a%10 < b%10; }
struct Fuenfer {
bool operator()(int a, int b) const { return a%5 < b% 5; }
};
int main() {
// Funktor
set<int, Fuenfer> ff1;
ff1.insert(5);
set ff2({5}, Fuenfer{});
set ff3(initializer_list<int>({}), Fuenfer{});
// Lambda
set<int,function<bool(int,int)>> ll1([](auto a,auto b){return a%3<b%3;});
ll1.insert(3);
auto lcomp = [](int a, int b) { return a%3 < b%3; };
set<int, decltype(lcomp)> ll2(lcomp);
ll2.insert(3);
set ll3({3}, lcomp);
// Funktionszeiger
set<int, bool(*)(int,int)> zz1(&fcompZehner); // C-Stil
zz1.insert(10);
set<int, function<bool(int,int)>> zz2(&fcompZehner); // C++-Stil
zz2.insert(10);
set<int, decltype(&fcompZehner)> zz3(&fcompZehner); // C++-Stil
zz3.insert(10);
}
Godbolt Listing lst-0761-godb.cpp, https://godbolt.org/z/1Eoh9aoas:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/1Eoh9aoas
#include <set>
#include <functional> // function
using std::set; using std::function; using std::initializer_list;
bool fcompZehner(int a, int b) { return a%10 < b%10; }
struct Fuenfer {
bool operator()(int a, int b) const { return a%5 < b% 5; }
};
int main() {
// Funktor
set<int, Fuenfer> ff1;
ff1.insert(5);
set ff2({5}, Fuenfer{});
set ff3(initializer_list<int>({}), Fuenfer{});
// Lambda
set<int,function<bool(int,int)>> ll1([](auto a,auto b){return a%3<b%3;});
ll1.insert(3);
auto lcomp = [](int a, int b) { return a%3 < b%3; };
set<int, decltype(lcomp)> ll2(lcomp);
ll2.insert(3);
set ll3({3}, lcomp);
// Funktionszeiger
set<int, bool(*)(int,int)> zz1(&fcompZehner); // C-Stil
zz1.insert(10);
set<int, function<bool(int,int)>> zz2(&fcompZehner); // C++-Stil
zz2.insert(10);
set<int, decltype(&fcompZehner)> zz3(&fcompZehner); // C++-Stil
zz3.insert(10);
}
Listing 24.50: Es gibt wieder mehrere Möglichkeiten, beim Konstruieren Elemente anzugeben.
Book listing lst-0762-book.cpp:
// https://godbolt.org/z/56rb9qfed
// ohne Argumente
set<int> leer{};
cout <<= leer; // Ausgabe:
// Initialisierungsliste
set liste{ 1,1,2,2,3,3,4,4,5,5 }; // set übernimmt keine Doppelten
cout <<= liste; // Ausgabe: 1 2 3 4 5
// Kopie
set copy(liste);
cout <<= copy; // Ausgabe: 1 2 3 4 5
// Iteratorpaar
set from_to( std::next(liste.begin()), std::prev(liste.end()));
cout <<= from_to; // Ausgabe: 2 3 4
// Range
set gerade(from_range, liste | vs::filter([](int i){ return i%2; }));
cout <<= from_to; // Ausgabe: 2 4
Godbolt Listing lst-0762-godb.cpp, https://godbolt.org/z/56rb9qfed:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/56rb9qfed
// ohne Argumente
set<int> leer{};
cout <<= leer; // Ausgabe:
// Initialisierungsliste
set liste{ 1,1,2,2,3,3,4,4,5,5 }; // set übernimmt keine Doppelten
cout <<= liste; // Ausgabe: 1 2 3 4 5
// Kopie
set copy(liste);
cout <<= copy; // Ausgabe: 1 2 3 4 5
// Iteratorpaar
set from_to( std::next(liste.begin()), std::prev(liste.end()));
cout <<= from_to; // Ausgabe: 2 3 4
// Range
set gerade(from_range, liste | vs::filter([](int i){ return i%2; }));
cout <<= from_to; // Ausgabe: 2 4
GodboltId:1dTPEd3nP
Book listing lst-0763-book.cpp:
// https://godbolt.org/z/1dTPEd3nP
set quelle{1,2,3,4,5};
cout <<= quelle; // Ausgabe: 1 2 3 4 5
set ziel( std::move(quelle) ); // verschieben statt kopieren
cout <<= quelle; // Ausgabe:
cout <<= ziel; // Ausgabe: 1 2 3 4 5
Godbolt Listing lst-0763-godb.cpp, https://godbolt.org/z/1dTPEd3nP:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/1dTPEd3nP
set quelle{1,2,3,4,5};
cout <<= quelle; // Ausgabe: 1 2 3 4 5
set ziel( std::move(quelle) ); // verschieben statt kopieren
cout <<= quelle; // Ausgabe:
cout <<= ziel; // Ausgabe: 1 2 3 4 5
GodboltId:8eGvWY45o
Book listing lst-0764-book.cpp:
// https://godbolt.org/z/8eGvWY45o
set quelle{1,2,3,4,5};
set<int> ziel{};
set<int> ziel2{};
cout <<= quelle; // Ausgabe: 1 2 3 4 5
cout <<= ziel; // Ausgabe:
cout <<= ziel2; // Ausgabe:
ziel = quelle; // nachträglich kopieren
cout <<= quelle; // Ausgabe: 1 2 3 4 5
cout <<= ziel; // Ausgabe: 1 2 3 4 5
ziel2 = std::move(quelle); // verschieben
cout <<= quelle; // Ausgabe:
cout <<= ziel2; // Ausgabe: 1 2 3 4 5
Godbolt Listing lst-0764-godb.cpp, https://godbolt.org/z/8eGvWY45o:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/8eGvWY45o
set quelle{1,2,3,4,5};
set<int> ziel{};
set<int> ziel2{};
cout <<= quelle; // Ausgabe: 1 2 3 4 5
cout <<= ziel; // Ausgabe:
cout <<= ziel2; // Ausgabe:
ziel = quelle; // nachträglich kopieren
cout <<= quelle; // Ausgabe: 1 2 3 4 5
cout <<= ziel; // Ausgabe: 1 2 3 4 5
ziel2 = std::move(quelle); // verschieben
cout <<= quelle; // Ausgabe:
cout <<= ziel2; // Ausgabe: 1 2 3 4 5
Listing 24.51: Statt »assign« können Sie das Copy-and-swap-Idiom verwenden.
Book listing lst-0765-book.cpp:
// https://godbolt.org/z/1vGPo9a99
#include <vector>
// …
set data{1,2,3,4,5};
std::vector quelle{10, 20, 30, 40, 50};
// Es gibt kein set::assign:
data.assign(quelle.begin(), quelle.end()); // (ERR) kein set::assign
// Simulieren Sie es also mittels eines temporären set:
set temp(quelle.begin(), quelle.end()); // aus Quelle kopieren …
data.swap(temp); // … Inhalte effizient vertauschen
cout <<= data; // Ausgabe: 10 20 30 40 50
// … oder per vorherigem clear und darauffolgendem insert:
data.clear(); // leeren …
data.insert(quelle.begin(), quelle.end()); // … und einfügen
cout <<= data; // Ausgabe: 10 20 30 40 50
Godbolt Listing lst-0765-godb.cpp, https://godbolt.org/z/1vGPo9a99:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/1vGPo9a99
#include <vector>
// …
set data{1,2,3,4,5};
std::vector quelle{10, 20, 30, 40, 50};
// Es gibt kein set::assign:
data.assign(quelle.begin(), quelle.end()); // (ERR) kein set::assign
// Simulieren Sie es also mittels eines temporären set:
set temp(quelle.begin(), quelle.end()); // aus Quelle kopieren …
data.swap(temp); // … Inhalte effizient vertauschen
cout <<= data; // Ausgabe: 10 20 30 40 50
// … oder per vorherigem clear und darauffolgendem insert:
data.clear(); // leeren …
data.insert(quelle.begin(), quelle.end()); // … und einfügen
cout <<= data; // Ausgabe: 10 20 30 40 50
Listing 24.52: Zum Einfügen eines einzelnen Elements nehmen Sie »insert« oder »emplace«.
Book listing lst-0766-book.cpp:
// https://godbolt.org/z/PjEKKben4
// …
template<typename IT> ostream& operator<<(ostream& os,const pair<IT,bool> wo)
{ return os << (wo.second ? "ja" : "nein"); }
struct Punkt {
double x_, y_;
Punkt(double x, double y) : x_{x}, y_{y} {}
auto operator<=>(const Punkt&) const = default;
friend ostream& operator<<(ostream &os, const Punkt &a) {
return os << "(" << a.x_ << ',' << a.y_<< ")";
}
};
int main() {
set data{ 10, 20, 30, 40, 50, 60, 70 };
auto wo = data.insert(35); // fügt zwischen 30 und 40 ein
cout << "neu? " << wo << '\n'; // Ausgabe: neu? ja
wo = data.insert(40); // gibt es schon, fügt also nicht ein
cout << "neu? " << wo << '\n'; // Ausgabe: neu? nein
set<Punkt> punkte{};
punkte.insert( Punkt{3.50,7.25} ); // temporärer Wert
punkte.emplace(1.25, 2.00); // Konstruktorargumente
cout <<= punkte; // Ausgabe: (1.25,2) (3.5,7.25)
}
Godbolt Listing lst-0766-godb.cpp, https://godbolt.org/z/PjEKKben4:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/PjEKKben4
// …
template<typename IT> ostream& operator<<(ostream& os,const pair<IT,bool> wo)
{ return os << (wo.second ? "ja" : "nein"); }
struct Punkt {
double x_, y_;
Punkt(double x, double y) : x_{x}, y_{y} {}
auto operator<=>(const Punkt&) const = default;
friend ostream& operator<<(ostream &os, const Punkt &a) {
return os << "(" << a.x_ << ',' << a.y_<< ")";
}
};
int main() {
set data{ 10, 20, 30, 40, 50, 60, 70 };
auto wo = data.insert(35); // fügt zwischen 30 und 40 ein
cout << "neu? " << wo << '\n'; // Ausgabe: neu? ja
wo = data.insert(40); // gibt es schon, fügt also nicht ein
cout << "neu? " << wo << '\n'; // Ausgabe: neu? nein
set<Punkt> punkte{};
punkte.insert( Punkt{3.50,7.25} ); // temporärer Wert
punkte.emplace(1.25, 2.00); // Konstruktorargumente
cout <<= punkte; // Ausgabe: (1.25,2) (3.5,7.25)
}
Listing 24.53: Die Rückgabe können Sie beim Einfügen sortierter Bereiche wiederverwenden.
Book listing lst-0767-book.cpp:
// https://godbolt.org/z/qzaj79bor
set data{ 10, 20, 30, 40, 50, 60, 70 };
set<int> ziel;
auto hinweis = ziel.begin();
for(auto &e : data) {
hinweis = // Einfügeposition in nächster Runde nutzen
ziel.insert(hinweis, e); // Hinweis hilft, weil data sortiert ist
}
Godbolt Listing lst-0767-godb.cpp, https://godbolt.org/z/qzaj79bor:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/qzaj79bor
set data{ 10, 20, 30, 40, 50, 60, 70 };
set<int> ziel;
auto hinweis = ziel.begin();
for(auto &e : data) {
hinweis = // Einfügeposition in nächster Runde nutzen
ziel.insert(hinweis, e); // Hinweis hilft, weil data sortiert ist
}
Listing 24.54: Nehmen Sie das gleiche insert bei sequenziellen und assoziativen Containern.
Book listing lst-0768-book.cpp:
// https://godbolt.org/z/nW3Gxe5Ye
#include <set>
#include <vector>
#include <iostream>
using std::cout; using std::ostream; using std::set; using std::vector;
template<typename Container>
void insFive(Container& cont, int a, int b, int c, int d, int e) {
auto it = cont.end();
for(int x : { a, b, c, d, e }) {
it = cont.insert(it, x); // geht mit vector, set etc.
}
}
int main() {
vector<int> dataVec{ };
insFive(dataVec, 9, 2, 2, 0, 4 );
for(auto e : dataVec) cout <<e<<' ';
cout << '\n'; // Ausgabe: 4 0 2 2 9
set<int> dataSet{ };
insFive(dataSet, 9, 4, 2, 2, 0);
for(auto e : dataSet) cout <<e<<' ';
cout << '\n'; // Ausgabe: 0 2 4 9
}
Godbolt Listing lst-0768-godb.cpp, https://godbolt.org/z/nW3Gxe5Ye:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/nW3Gxe5Ye
#include <set>
#include <vector>
#include <iostream>
using std::cout; using std::ostream; using std::set; using std::vector;
template<typename Container>
void insFive(Container& cont, int a, int b, int c, int d, int e) {
auto it = cont.end();
for(int x : { a, b, c, d, e }) {
it = cont.insert(it, x); // geht mit vector, set etc.
}
}
int main() {
vector<int> dataVec{ };
insFive(dataVec, 9, 2, 2, 0, 4 );
for(auto e : dataVec) cout <<e<<' ';
cout << '\n'; // Ausgabe: 4 0 2 2 9
set<int> dataSet{ };
insFive(dataSet, 9, 4, 2, 2, 0);
for(auto e : dataSet) cout <<e<<' ';
cout << '\n'; // Ausgabe: 0 2 4 9
}
Listing 24.55: Sie können auch mehrere Elemente einfügen.
Book listing lst-0769-book.cpp:
// https://godbolt.org/z/rTvovhr5M
#include <vector>
set data{ 10, 20, 30, };
data.insert( { 40, 50, 60, 70 }); // Initialisierungsliste
std::vector neu{ 5, 25, 35, 15, 25, 75, 95 };
data.insert( neu.cbegin()+1, neu.cend()-1 ); // Bereich
cout <<= data; // Ausgabe: 10 15 20 25 30 35 40 50 60 70 75
Godbolt Listing lst-0769-godb.cpp, https://godbolt.org/z/rTvovhr5M:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/rTvovhr5M
#include <vector>
set data{ 10, 20, 30, };
data.insert( { 40, 50, 60, 70 }); // Initialisierungsliste
std::vector neu{ 5, 25, 35, 15, 25, 75, 95 };
data.insert( neu.cbegin()+1, neu.cend()-1 ); // Bereich
cout <<= data; // Ausgabe: 10 15 20 25 30 35 40 50 60 70 75
Listing 24.56: Dies sind die »set«-Suchfunktionen.
Book listing lst-0770-book.cpp:
// https://godbolt.org/z/xnv9Wbxbz
#include <set>
#include <iostream>
using std::cout; using std::ostream; using std::set;
void suchmal(const set<int>&data, int was, ostream&os) {
os << was << "? ";
// enthält
auto drin = data.contains(was); // C++20
os << "drin:" << (drin ? "ja." : "nein."); // enthält prüfen
auto wo = data.find(was);
if(wo != data.end()) {
os << " gefunden:" << *wo << " ";
} else {
os << " nicht gefunden. ";
}
auto lo = data.lower_bound(was);
if(lo != data.end()) {
os << "lo:" << *lo;
} else {
os << "lo:-";
}
auto up = data.upper_bound(was);
if(up != data.end()) {
os << " up:" << *up;
} else {
os << " up:-";
}
// [lo,up] ist nun das Gleiche, was equal_range geliefert hätte
os << " Bereich:{";
for( ; lo != up; ++ lo) {
os << *lo << ' ';
}
os << "}";
// zählen
os << " C:" << data.count(was) // Treffer zählen
<< "\n";
}
int main() {
set data{ 10, 20, 30, 40, 50, 60 };
suchmal(data, 20, cout); // 20? drin:ja. gefunden:20 lo:20 up:30 Bereich:{20 } C:1
suchmal(data, 25, cout); // 25? drin:nein. lo:30 up:30 Bereich:{} C:0
suchmal(data, 10, cout); // 10? drin:ja. gefunden:10 lo:10 up:20 Bereich:{10 } C:1
suchmal(data, 60, cout); // 60? drin:ja. gefunden:60 lo:60 up:- Bereich:{60 } C:1
suchmal(data, 5, cout); // 5? drin:nein. lo:10 up:10 Bereich:{} C:0
suchmal(data, 99, cout); // 99? drin:nein. lo:- up:- Bereich:{} C:0
}
Godbolt Listing lst-0770-godb.cpp, https://godbolt.org/z/xnv9Wbxbz:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/xnv9Wbxbz
#include <set>
#include <iostream>
using std::cout; using std::ostream; using std::set;
void suchmal(const set<int>&data, int was, ostream&os) {
os << was << "? ";
// enthält
auto drin = data.contains(was); // C++20
os << "drin:" << (drin ? "ja." : "nein."); // enthält prüfen
auto wo = data.find(was);
if(wo != data.end()) {
os << " gefunden:" << *wo << " ";
} else {
os << " nicht gefunden. ";
}
auto lo = data.lower_bound(was);
if(lo != data.end()) {
os << "lo:" << *lo;
} else {
os << "lo:-";
}
auto up = data.upper_bound(was);
if(up != data.end()) {
os << " up:" << *up;
} else {
os << " up:-";
}
// [lo,up] ist nun das Gleiche, was equal_range geliefert hätte
os << " Bereich:{";
for( ; lo != up; ++ lo) {
os << *lo << ' ';
}
os << "}";
// zählen
os << " C:" << data.count(was) // Treffer zählen
<< "\n";
}
int main() {
set data{ 10, 20, 30, 40, 50, 60 };
suchmal(data, 20, cout); // 20? drin:ja. gefunden:20 lo:20 up:30 Bereich:{20 } C:1
suchmal(data, 25, cout); // 25? drin:nein. lo:30 up:30 Bereich:{} C:0
suchmal(data, 10, cout); // 10? drin:ja. gefunden:10 lo:10 up:20 Bereich:{10 } C:1
suchmal(data, 60, cout); // 60? drin:ja. gefunden:60 lo:60 up:- Bereich:{60 } C:1
suchmal(data, 5, cout); // 5? drin:nein. lo:10 up:10 Bereich:{} C:0
suchmal(data, 99, cout); // 99? drin:nein. lo:- up:- Bereich:{} C:0
}
Listing 24.57: Sie können mit nicht identischen Schlüsseln suchen, wenn diese äquivalent sind.
Book listing lst-0771-book.cpp:
// https://godbolt.org/z/jGfeT94as
#include <string>
#include <set>
#include <iostream>
#include <tuple> // tuple, tie
using std::string; using std::set; using std::cout; using std::tie;
struct Hobbit {
string vorname;
string nachname;
Hobbit(const string v, const string n) : vorname{v}, nachname{n} {}
};
struct CompNachname {
bool operator()(const Hobbit& x, const Hobbit& y) const { // normales <
return tie(x.nachname, x.vorname) < tie(y.nachname, y.vorname);
}
using is_transparent = std::true_type; // für find erlaubt
bool operator()(const Hobbit& x, const string& y) const { // für find etc.
return x.nachname < y;
}
bool operator()(const string& x, const Hobbit& y) const { // für find etc.
return x < y.nachname;
}
};
int main() {
using namespace std::literals; // erlaube "…"s
set<Hobbit,CompNachname> hobbits;
hobbits.emplace( "Frodo", "Baggins" );
hobbits.emplace( "Sam", "Gamgee" );
auto f1 = hobbits.find( Hobbit{"Frodo", "Baggins"} ); // ganzer Schlüssel
if(f1 != hobbits.end()) {
cout << "gefunden: " << f1->vorname << '\n'; // Frodo
}
auto f2 = hobbits.find( "Gamgee"s ); // äquivalenter Schlüssel
if(f2 != hobbits.end()) {
cout << "gefunden: " << f2->vorname << '\n'; // Sam
}
}
Godbolt Listing lst-0771-godb.cpp, https://godbolt.org/z/jGfeT94as:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/jGfeT94as
#include <string>
#include <set>
#include <iostream>
#include <tuple> // tuple, tie
using std::string; using std::set; using std::cout; using std::tie;
struct Hobbit {
string vorname;
string nachname;
Hobbit(const string v, const string n) : vorname{v}, nachname{n} {}
};
struct CompNachname {
bool operator()(const Hobbit& x, const Hobbit& y) const { // normales <
return tie(x.nachname, x.vorname) < tie(y.nachname, y.vorname);
}
using is_transparent = std::true_type; // für find erlaubt
bool operator()(const Hobbit& x, const string& y) const { // für find etc.
return x.nachname < y;
}
bool operator()(const string& x, const Hobbit& y) const { // für find etc.
return x < y.nachname;
}
};
int main() {
using namespace std::literals; // erlaube "…"s
set<Hobbit,CompNachname> hobbits;
hobbits.emplace( "Frodo", "Baggins" );
hobbits.emplace( "Sam", "Gamgee" );
auto f1 = hobbits.find( Hobbit{"Frodo", "Baggins"} ); // ganzer Schlüssel
if(f1 != hobbits.end()) {
cout << "gefunden: " << f1->vorname << '\n'; // Frodo
}
auto f2 = hobbits.find( "Gamgee"s ); // äquivalenter Schlüssel
if(f2 != hobbits.end()) {
cout << "gefunden: " << f2->vorname << '\n'; // Sam
}
}
Listing 24.58: »erase« löscht ein oder mehrere Elemente.
Book listing lst-0773-book.cpp:
// https://godbolt.org/z/xW9bTqfG4
set data{ 10, 20, 30, 40, 50, 60, 70 };
auto lo = data.lower_bound(35);
auto up = data.upper_bound(55);
data.erase(lo, up); // löscht alle Zahlen zwischen 35 und 55
cout <<= data; // Ausgabe: 10 20 30 60 70
lo = data.lower_bound(20);
up = data.upper_bound(60);
data.erase(lo, up); // löscht inklusive 60, weil up auf 70 verweist
cout <<= data; // Ausgabe: 10 70
auto n = data.erase(69); // löscht nichts
cout << "Anzahl entfernter Elemente: "<< n << '\n'; // Ausgabe: Anzahl … 0
n = data.erase(70); // löscht ein Element
cout << "Anzahl entfernter Elemente: "<< n << '\n'; // Ausgabe: Anzahl … 1
cout <<= data; // Ausgabe: 10
Godbolt Listing lst-0773-godb.cpp, https://godbolt.org/z/xW9bTqfG4:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/xW9bTqfG4
set data{ 10, 20, 30, 40, 50, 60, 70 };
auto lo = data.lower_bound(35);
auto up = data.upper_bound(55);
data.erase(lo, up); // löscht alle Zahlen zwischen 35 und 55
cout <<= data; // Ausgabe: 10 20 30 60 70
lo = data.lower_bound(20);
up = data.upper_bound(60);
data.erase(lo, up); // löscht inklusive 60, weil up auf 70 verweist
cout <<= data; // Ausgabe: 10 70
auto n = data.erase(69); // löscht nichts
cout << "Anzahl entfernter Elemente: "<< n << '\n'; // Ausgabe: Anzahl … 0
n = data.erase(70); // löscht ein Element
cout << "Anzahl entfernter Elemente: "<< n << '\n'; // Ausgabe: Anzahl … 1
cout <<= data; // Ausgabe: 10
Listing 24.59: Mit »[]« erzeugen Sie als Seiteneffekt eventuell einen Eintrag.
Book listing lst-0774-book.cpp:
// https://godbolt.org/z/zWa58dYYq
#include <map>
#include <iostream>
using std::map; using std::cout;
int main() {
map<int,char> alpha;
cout << alpha.size() << '\n'; // 0 natürlich
if( alpha[5] == '3' ) { /* ... */ }
cout << alpha.size() << '\n'; // nun 1
char x = alpha[99]; // klappt
cout << alpha.size() << '\n'; // und nun 2
}
Godbolt Listing lst-0774-godb.cpp, https://godbolt.org/z/zWa58dYYq:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/zWa58dYYq
#include <map>
#include <iostream>
using std::map; using std::cout;
int main() {
map<int,char> alpha;
cout << alpha.size() << '\n'; // 0 natürlich
if( alpha[5] == '3' ) { /* ... */ }
cout << alpha.size() << '\n'; // nun 1
char x = alpha[99]; // klappt
cout << alpha.size() << '\n'; // und nun 2
}
Listing 24.60: Dies ist die Schablone für die Beispiellistings dieses Abschnitts zur »map«.
Book listing lst-0775-book.cpp:
// https://godbolt.org/z/Eovd71TbT
#include <map> // die Hauptsache
#include <iostream> // zur Ausgabe
#include <string> // gerne mal Schlüssel oder Ziel
using std::map; using std::cout; using std::string;
template<typename Key, typename Trg, typename Comp>
std::ostream& operator<<=(std::ostream&os, const map<Key,Trg,Comp>&data) {
for(auto &e : data) os << e.first << ":" << e.second << ' ';
return os << '\n'; // '<<=' statt '<<' für Zeilenumbruch
}
int main() {
// Beispielcode hier
}
Godbolt Listing lst-0775-godb.cpp, https://godbolt.org/z/Eovd71TbT:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Eovd71TbT
#include <map> // die Hauptsache
#include <iostream> // zur Ausgabe
#include <string> // gerne mal Schlüssel oder Ziel
using std::map; using std::cout; using std::string;
template<typename Key, typename Trg, typename Comp>
std::ostream& operator<<=(std::ostream&os, const map<Key,Trg,Comp>&data) {
for(auto &e : data) os << e.first << ":" << e.second << ' ';
return os << '\n'; // '<<=' statt '<<' für Zeilenumbruch
}
int main() {
// Beispielcode hier
}
Listing 24.61: Auch bei einer »map« können Sie eine eigene Vergleichsfunktion mitgeben.
Book listing lst-0776-book.cpp:
// https://godbolt.org/z/nfs15n1Mn
#include <cstdio> // toupper, tolower
// …
auto comp = [](char a, char b) { return toupper(a) < toupper(b); };
map<char,int,decltype(comp)> lets(comp); // als Templateparameter und Argument
lets['a'] = 1;
lets['B'] = 2;
lets['c'] = 3;
lets['A'] = 4; // überschreibt Position 'a'
cout <<= lets; // Ausgabe: a:4 B:2 c:3
struct Comp { // Funktor
bool operator()(char a, char b) const { return toupper(a) < toupper(b); }
};
map<char,int,Comp> lets2; // hier reicht der Templateparameter
Godbolt Listing lst-0776-godb.cpp, https://godbolt.org/z/nfs15n1Mn:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/nfs15n1Mn
#include <cstdio> // toupper, tolower
// …
auto comp = [](char a, char b) { return toupper(a) < toupper(b); };
map<char,int,decltype(comp)> lets(comp); // als Templateparameter und Argument
lets['a'] = 1;
lets['B'] = 2;
lets['c'] = 3;
lets['A'] = 4; // überschreibt Position 'a'
cout <<= lets; // Ausgabe: a:4 B:2 c:3
struct Comp { // Funktor
bool operator()(char a, char b) const { return toupper(a) < toupper(b); }
};
map<char,int,Comp> lets2; // hier reicht der Templateparameter
Listing 24.62: Die Initialisierungsliste muss »pair«-Elemente enthalten.
Book listing lst-0778-book.cpp:
// https://godbolt.org/z/79xx8ddoY
using std::pair; using std::make_pair;
namespace literal_p { // benutzerdefinierte Literale besser in Namespace packen
constexpr pair<char,char> operator "" _p(const char* s, size_t len) {
return len>=2 ?make_pair(s[0], s[1]) : make_pair( '-', '-' );
} }
struct Q {
char a_; int n_;
Q(char a, int n) : a_{a}, n_{n} {}
operator pair<const char,int>() { return make_pair(a_, n_); }
};
// …
// explizite Paare:
map<int,int> nums { pair<int,int>(3,4), make_pair(7,8), make_pair(11,23) };
map nums2 { pair<int,int>(6,1), make_pair(5,2) };
// implizite Paare aus Initialisierungslisten:
map<int,char> numch{{1,'a'},{2,'b'},{3,'c'}};
map<int,int> nums3 { {7,2}, {9,4} };
using namespace literal_p;
map<char,char> pmap { "ab"_p, "cd"_p, "ef"_p }; // Umweg über eigenes Literal
cout <<= pmap; // Ausgabe: a:b c:d e:f
map<char,int> qmap{Q('a',1),Q('b',2),Q('c',3)}; // implizite Umwandlungen
cout <<= qmap; // Ausgabe: a:1 b:2 c:3
Godbolt Listing lst-0778-godb.cpp, https://godbolt.org/z/79xx8ddoY:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/79xx8ddoY
using std::pair; using std::make_pair;
namespace literal_p { // benutzerdefinierte Literale besser in Namespace packen
constexpr pair<char,char> operator "" _p(const char* s, size_t len) {
return len>=2 ?make_pair(s[0], s[1]) : make_pair( '-', '-' );
} }
struct Q {
char a_; int n_;
Q(char a, int n) : a_{a}, n_{n} {}
operator pair<const char,int>() { return make_pair(a_, n_); }
};
// …
// explizite Paare:
map<int,int> nums { pair<int,int>(3,4), make_pair(7,8), make_pair(11,23) };
map nums2 { pair<int,int>(6,1), make_pair(5,2) };
// implizite Paare aus Initialisierungslisten:
map<int,char> numch{{1,'a'},{2,'b'},{3,'c'}};
map<int,int> nums3 { {7,2}, {9,4} };
using namespace literal_p;
map<char,char> pmap { "ab"_p, "cd"_p, "ef"_p }; // Umweg über eigenes Literal
cout <<= pmap; // Ausgabe: a:b c:d e:f
map<char,int> qmap{Q('a',1),Q('b',2),Q('c',3)}; // implizite Umwandlungen
cout <<= qmap; // Ausgabe: a:1 b:2 c:3
Listing 24.63: Ein einzelnes neues Element geben Sie als Paar an.
Book listing lst-0779-book.cpp:
// https://godbolt.org/z/bzvrPefvY
map<int,string> plz2ort;
plz2ort.insert(std::make_pair(53227, "Bonn"));
plz2ort.emplace(50667, "Koeln");
cout <<= plz2ort; // Ausgabe: 50667:Koeln 53227:Bonn
map<string,int> ort2plz;
ort2plz.emplace("Koeln", 50667);
ort2plz.emplace("Koeln", 51063); // überschreibt nicht
cout <<= ort2plz; // Ausgabe: Koeln:50667
Godbolt Listing lst-0779-godb.cpp, https://godbolt.org/z/bzvrPefvY:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/bzvrPefvY
map<int,string> plz2ort;
plz2ort.insert(std::make_pair(53227, "Bonn"));
plz2ort.emplace(50667, "Koeln");
cout <<= plz2ort; // Ausgabe: 50667:Koeln 53227:Bonn
map<string,int> ort2plz;
ort2plz.emplace("Koeln", 50667);
ort2plz.emplace("Koeln", 51063); // überschreibt nicht
cout <<= ort2plz; // Ausgabe: Koeln:50667
Listing 24.64: Mit »operator[]« automatisch erzeugen und gleich überschreiben
Book listing lst-0780-book.cpp:
// https://godbolt.org/z/7h3vsWvYG
map<string,int> zwerge;
zwerge.emplace("Fili", 2859);
cout << zwerge["Fili"] << '\n'; // Ausgabe: 2859
cout << zwerge["Dori"] << '\n'; // neu erzeugt. Ausgabe: 0
zwerge["Kili"] = 2846; // neu erzeugt und gleich überschrieben
cout << zwerge["Kili"] << '\n'; // Ausgabe: 2846
cout <<= zwerge; // Ausgabe: Dori:0 Fili:2859 Kili:2846
Godbolt Listing lst-0780-godb.cpp, https://godbolt.org/z/7h3vsWvYG:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/7h3vsWvYG
map<string,int> zwerge;
zwerge.emplace("Fili", 2859);
cout << zwerge["Fili"] << '\n'; // Ausgabe: 2859
cout << zwerge["Dori"] << '\n'; // neu erzeugt. Ausgabe: 0
zwerge["Kili"] = 2846; // neu erzeugt und gleich überschrieben
cout << zwerge["Kili"] << '\n'; // Ausgabe: 2846
cout <<= zwerge; // Ausgabe: Dori:0 Fili:2859 Kili:2846
Listing 24.65: Sie können den Wert eines Ziels ändern.
Book listing lst-0781-book.cpp:
// https://godbolt.org/z/7E6cr8GE9
map<string,string> data { {"Hans","Albers"}, {"Heinz","Ruehmann" }, };
cout <<= data; // Hans:Albers Heinz:Ruehmann
data.rbegin()->second = "Erhardt"; // Ziel überschreiben
cout <<= data; // Hans:Albers Heinz:Erhardt
Godbolt Listing lst-0781-godb.cpp, https://godbolt.org/z/7E6cr8GE9:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/7E6cr8GE9
map<string,string> data { {"Hans","Albers"}, {"Heinz","Ruehmann" }, };
cout <<= data; // Hans:Albers Heinz:Ruehmann
data.rbegin()->second = "Erhardt"; // Ziel überschreiben
cout <<= data; // Hans:Albers Heinz:Erhardt
Listing 24.66: Iteratoren von »map« sind vom Typ »pair«.
Book listing lst-0782-book.cpp:
// https://godbolt.org/z/16T5dob75
map<char,int> data { { 'a',1}, {'b',2}, {'c',3} };
for(auto it=data.rbegin(); it!=data.rend(); ++it) { // rückwärts
cout << it->first << ':' << it->second << ' '; // mit -> dereferenzieren
}
cout << '\n'; // Ausgabe: c:3 b:2 a:1
for(auto &e : data) { // vorwärts, nimmt begin() und end()
cout << e.first << ':' << e.second << ' '; // Paar, Elementzugriff mit .
}
cout << '\n'; // Ausgabe: a:1 b:2 c:3
Godbolt Listing lst-0782-godb.cpp, https://godbolt.org/z/16T5dob75:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/16T5dob75
map<char,int> data { { 'a',1}, {'b',2}, {'c',3} };
for(auto it=data.rbegin(); it!=data.rend(); ++it) { // rückwärts
cout << it->first << ':' << it->second << ' '; // mit -> dereferenzieren
}
cout << '\n'; // Ausgabe: c:3 b:2 a:1
for(auto &e : data) { // vorwärts, nimmt begin() und end()
cout << e.first << ':' << e.second << ' '; // Paar, Elementzugriff mit .
}
cout << '\n'; // Ausgabe: a:1 b:2 c:3
Listing 24.67: Sie können »operator[]« nicht auf einer »const map« verwenden.
Book listing lst-0783-book.cpp:
// https://godbolt.org/z/54zqqhzh6
string such7(const map<int,string> &data) {
return data[7]; // (ERR) non-const-Methode auf const-Parameter
}
string such5(const map<int,string> &data) {
auto it = data.find(5); // nicht automatisch einfügend
return it==data.end() ? string{} : it->second;
}
// …
map<int,string> zwerge{ {1,"eins"}, {3,"drei"}, {5,"fuenf"}, {7,"sieben"} };
cout << such7(zwerge) << '\n';
cout << such5(zwerge) << '\n'; // Ausgabe: fuenf
Godbolt Listing lst-0783-godb.cpp, https://godbolt.org/z/54zqqhzh6:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/54zqqhzh6
string such7(const map<int,string> &data) {
return data[7]; // (ERR) non-const-Methode auf const-Parameter
}
string such5(const map<int,string> &data) {
auto it = data.find(5); // nicht automatisch einfügend
return it==data.end() ? string{} : it->second;
}
// …
map<int,string> zwerge{ {1,"eins"}, {3,"drei"}, {5,"fuenf"}, {7,"sieben"} };
cout << such7(zwerge) << '\n';
cout << such5(zwerge) << '\n'; // Ausgabe: fuenf
Listing 24.68: Dies ist die Schablone für die Beispiellistings dieses Abschnitts zu »multiset«.
Book listing lst-0784-book.cpp:
// https://godbolt.org/z/PYbexWex3
#include <set> // multiset
#include <iostream>
using std::multiset; using std::cout;
template<typename Elem, typename Comp>
std::ostream& operator<<=(std::ostream&os, const multiset<Elem,Comp>&data) {
for(auto &e : data) {
os << e << ' ';
}
return os << '\n'; // '<<=' statt '<<' für Zeilenumbruch
}
int main() {
// Beispielcode hier
}
Godbolt Listing lst-0784-godb.cpp, https://godbolt.org/z/PYbexWex3:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/PYbexWex3
#include <set> // multiset
#include <iostream>
using std::multiset; using std::cout;
template<typename Elem, typename Comp>
std::ostream& operator<<=(std::ostream&os, const multiset<Elem,Comp>&data) {
for(auto &e : data) {
os << e << ' ';
}
return os << '\n'; // '<<=' statt '<<' für Zeilenumbruch
}
int main() {
// Beispielcode hier
}
Listing 24.69: Einträge werden sortiert, doppelte bleiben erhalten.
Book listing lst-0785-book.cpp:
// https://godbolt.org/z/Mej9GjT1j
#include <vector>
// …
multiset msinit{1,2,2,3,1}; // sortiert bei Initialisierung
cout <<= msinit; // Ausgabe: 1 1 2 2 3
std::vector in{ 7,7,7,7,7,7,7 };
std::set srange( in.begin(), in.end() ); // set entfernt doppelte
cout << srange.size() << ": " << *srange.begin() << '\n'; // Ausgabe: 1: 7
multiset msrange( in.begin(), in.end() ); // multiset erhält doppelte
cout <<= msrange; // Ausgabe: 7 7 7 7 7 7 7
Godbolt Listing lst-0785-godb.cpp, https://godbolt.org/z/Mej9GjT1j:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Mej9GjT1j
#include <vector>
// …
multiset msinit{1,2,2,3,1}; // sortiert bei Initialisierung
cout <<= msinit; // Ausgabe: 1 1 2 2 3
std::vector in{ 7,7,7,7,7,7,7 };
std::set srange( in.begin(), in.end() ); // set entfernt doppelte
cout << srange.size() << ": " << *srange.begin() << '\n'; // Ausgabe: 1: 7
multiset msrange( in.begin(), in.end() ); // multiset erhält doppelte
cout <<= msrange; // Ausgabe: 7 7 7 7 7 7 7
Listing 24.70: Die »multiset«-Suchfunktionen finden den Bereich der passenden Elemente.
Book listing lst-0786-book.cpp:
// https://godbolt.org/z/9hPqa5MfY
#include <string>
#include <iterator> // distance
#include <ranges> // subrange
struct Person {
std::string name;
friend bool operator<(const Person &a, const Person &b) {
// nur erster Buchstabe
return a.name.size()==0 ? true
: (b.name.size()==0 ? false : a.name[0] < b.name[0]);
}
};
// …
multiset data{ 1, 4,4, 2,2,2, 7, 9 };
auto [von1, bis1] = data.equal_range(2);
cout << "Anzahl 2en: "
<< std::distance(von1, bis1) << '\n'; // Ausgabe: Anzahl 2en: 3
auto [von2, bis2] = data.equal_range(5);
cout << "Anzahl 5en: "
<< std::distance(von2, bis2) << '\n'; // Ausgabe: Anzahl 5en: 0
multiset<Person> raum{
{"Karl"}, {"Kurt"}, {"Peter"}, {"Karl"}, {"Ken"}};
auto [p, q] = raum.equal_range(Person{"K"});
for(auto& p : std::ranges::subrange(p,q)) { // C++20-Range oder einfache Schleife
cout << p.name << ' ';
}
cout << '\n'; // Ausgabe: Karl Kurt Karl Ken
Godbolt Listing lst-0786-godb.cpp, https://godbolt.org/z/9hPqa5MfY:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/9hPqa5MfY
#include <string>
#include <iterator> // distance
#include <ranges> // subrange
struct Person {
std::string name;
friend bool operator<(const Person &a, const Person &b) {
// nur erster Buchstabe
return a.name.size()==0 ? true
: (b.name.size()==0 ? false : a.name[0] < b.name[0]);
}
};
// …
multiset data{ 1, 4,4, 2,2,2, 7, 9 };
auto [von1, bis1] = data.equal_range(2);
cout << "Anzahl 2en: "
<< std::distance(von1, bis1) << '\n'; // Ausgabe: Anzahl 2en: 3
auto [von2, bis2] = data.equal_range(5);
cout << "Anzahl 5en: "
<< std::distance(von2, bis2) << '\n'; // Ausgabe: Anzahl 5en: 0
multiset<Person> raum{
{"Karl"}, {"Kurt"}, {"Peter"}, {"Karl"}, {"Ken"}};
auto [p, q] = raum.equal_range(Person{"K"});
for(auto& p : std::ranges::subrange(p,q)) { // C++20-Range oder einfache Schleife
cout << p.name << ' ';
}
cout << '\n'; // Ausgabe: Karl Kurt Karl Ken
Listing 24.71: Dies ist die Schablone für die Listings dieses Abschnitts zur »multimap«.
Book listing lst-0787-book.cpp:
// https://godbolt.org/z/sfaEozjzq
#include <map> // die Hauptsache
#include <iostream> // zur Ausgabe
#include <string> // gerne mal Schlüssel oder Ziel
using std::multimap; using std::cout; using std::string;
template<typename Key, typename Trg, typename Cmp>
std::ostream& operator<<=(std::ostream&os, const multimap<Key,Trg,Cmp>&data){
for(auto &e : data) {
os << e.first << ":" << e.second << ' ';
}
return os << '\n'; // '<<=' statt '<<' für Zeilenumbruch
}
int main() {
// Beispielcode hier
}
Godbolt Listing lst-0787-godb.cpp, https://godbolt.org/z/sfaEozjzq:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/sfaEozjzq
#include <map> // die Hauptsache
#include <iostream> // zur Ausgabe
#include <string> // gerne mal Schlüssel oder Ziel
using std::multimap; using std::cout; using std::string;
template<typename Key, typename Trg, typename Cmp>
std::ostream& operator<<=(std::ostream&os, const multimap<Key,Trg,Cmp>&data){
for(auto &e : data) {
os << e.first << ":" << e.second << ' ';
}
return os << '\n'; // '<<=' statt '<<' für Zeilenumbruch
}
int main() {
// Beispielcode hier
}
Listing 24.72: Es landen alle Einträge in der »multimap«.
Book listing lst-0788-book.cpp:
// https://godbolt.org/z/6no9dW64d
multimap int2int{ std::make_pair(3,4) }; // multimap<int,int>
using namespace std::literals; // für ""s
multimap<int,string> numlang{
{7,"sieben"s}, {6,"six"s},
{7,"siete"s}, {6,"sechs"s},
{7,"seven"s}, {7,"yedi"s},
{8,"eight"s} };
cout <<= numlang; // Ausgabe: 6:six 6:sechs 7:sieben 7:siete 7:seven 7:yedi 8:eight
Godbolt Listing lst-0788-godb.cpp, https://godbolt.org/z/6no9dW64d:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/6no9dW64d
multimap int2int{ std::make_pair(3,4) }; // multimap<int,int>
using namespace std::literals; // für ""s
multimap<int,string> numlang{
{7,"sieben"s}, {6,"six"s},
{7,"siete"s}, {6,"sechs"s},
{7,"seven"s}, {7,"yedi"s},
{8,"eight"s} };
cout <<= numlang; // Ausgabe: 6:six 6:sechs 7:sieben 7:siete 7:seven 7:yedi 8:eight
Listing 24.73: »insert« und »emplace« bei der »multimap«
Book listing lst-0789-book.cpp:
// https://godbolt.org/z/dj68ej97r
using namespace std::literals; // für ""s
multimap<int,string> numlang{};
numlang.insert( std::make_pair(7, "seven"s) );
numlang.insert( std::pair<int,string>(7, "sieben"s) );
numlang.emplace( 7, "yedi"s );
cout <<= numlang; // Ausgabe: 7:seven 7:sieben 7:yedi
Godbolt Listing lst-0789-godb.cpp, https://godbolt.org/z/dj68ej97r:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/dj68ej97r
using namespace std::literals; // für ""s
multimap<int,string> numlang{};
numlang.insert( std::make_pair(7, "seven"s) );
numlang.insert( std::pair<int,string>(7, "sieben"s) );
numlang.emplace( 7, "yedi"s );
cout <<= numlang; // Ausgabe: 7:seven 7:sieben 7:yedi
Listing 24.74: »erase«mit einem Schlüssel kann mehrere Elemente löschen.
Book listing lst-0790-book.cpp:
// https://godbolt.org/z/TbvKTn4Px
multimap<char,int> vals{ {'c',1}, {'c',8}, {'g',1},
{'c',1}, {'a',7}, {'a',1}, {'c',2}, };
cout <<= vals; // Ausgabe: a:7 a:1 c:1 c:8 c:1 c:2 g:1
vals.erase( 'c' ); // löscht alle 'c's
cout <<= vals; // Ausgabe: a:7 a:1 g:1
vals.erase(vals.begin()); // löscht nur eines der 'a's
cout <<= vals; // Ausgabe: a:1 g:1
Godbolt Listing lst-0790-godb.cpp, https://godbolt.org/z/TbvKTn4Px:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/TbvKTn4Px
multimap<char,int> vals{ {'c',1}, {'c',8}, {'g',1},
{'c',1}, {'a',7}, {'a',1}, {'c',2}, };
cout <<= vals; // Ausgabe: a:7 a:1 c:1 c:8 c:1 c:2 g:1
vals.erase( 'c' ); // löscht alle 'c's
cout <<= vals; // Ausgabe: a:7 a:1 g:1
vals.erase(vals.begin()); // löscht nur eines der 'a's
cout <<= vals; // Ausgabe: a:1 g:1
Listing 24.75: Betreiben Sie ungeordnete assoziative Container niemals mit einer schlechten Hashfunktion.
Book listing lst-0791-book.cpp:
// https://godbolt.org/z/ejMv4ohse
#include <set> // set, multiset
#include <unordered_set> // unordered_set, unordered_multiset
#include <iostream>
#include <string>
#include <chrono> // Zeitmessung
using std::cout;
using namespace std::chrono;
long long millisSeit(steady_clock::time_point start) {
return duration_cast<milliseconds>(steady_clock::now()-start).count();
}
constexpr size_t ITERATIONS = 100'000;
template<typename Cont, typename Gen>
requires std::invocable<Gen, size_t> && // C++20-Concept
requires(Gen gen, size_t n) {{gen(n)} -> std::same_as<int>;} &&
std::same_as<typename Cont::value_type,int>
void timeStuff(std::string name, Cont data, Gen genNum) {
cout << name << "...";
auto start = steady_clock::now();
for(size_t idx=0; idx<ITERATIONS; ++idx) {
data.insert( genNum(idx) );
}
cout << " " << millisSeit(start) << " ms" << std::endl;
}
int alleGleich(size_t) { return 7; } // erzeugt immer die gleiche Zahl
int gestreut(size_t n) { return int(n); } // erzeugt unterschiedliche Zahlen
struct BadHash { // die schlechtestmögliche Hashfunktion als Funktor
size_t operator()(int) const { return 1uz; }
};
int main() {
std::multiset<int> m{};
timeStuff("multiset alleGleich ", m, &alleGleich);
timeStuff("multiset gestreut ", m, &gestreut);
std::set<int> s{};
timeStuff("set alleGleich ", s, &alleGleich);
timeStuff("set gestreut ", s, &gestreut);
std::unordered_multiset<int> um{};
timeStuff("unordered_multiset alleGleich ", um, &alleGleich);
timeStuff("unordered_multiset gestreut ", um, &gestreut);
std::unordered_multiset<int,BadHash> umb{};
timeStuff("unordered_multiset alleGleich badHash", umb, &alleGleich);
timeStuff("unordered_multiset gestreut badHash", umb, &gestreut);
}
Godbolt Listing lst-0791-godb.cpp, https://godbolt.org/z/ejMv4ohse:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/ejMv4ohse
#include <set> // set, multiset
#include <unordered_set> // unordered_set, unordered_multiset
#include <iostream>
#include <string>
#include <chrono> // Zeitmessung
using std::cout;
using namespace std::chrono;
long long millisSeit(steady_clock::time_point start) {
return duration_cast<milliseconds>(steady_clock::now()-start).count();
}
constexpr size_t ITERATIONS = 100'000;
template<typename Cont, typename Gen>
requires std::invocable<Gen, size_t> && // C++20-Concept
requires(Gen gen, size_t n) {{gen(n)} -> std::same_as<int>;} &&
std::same_as<typename Cont::value_type,int>
void timeStuff(std::string name, Cont data, Gen genNum) {
cout << name << "...";
auto start = steady_clock::now();
for(size_t idx=0; idx<ITERATIONS; ++idx) {
data.insert( genNum(idx) );
}
cout << " " << millisSeit(start) << " ms" << std::endl;
}
int alleGleich(size_t) { return 7; } // erzeugt immer die gleiche Zahl
int gestreut(size_t n) { return int(n); } // erzeugt unterschiedliche Zahlen
struct BadHash { // die schlechtestmögliche Hashfunktion als Funktor
size_t operator()(int) const { return 1uz; }
};
int main() {
std::multiset<int> m{};
timeStuff("multiset alleGleich ", m, &alleGleich);
timeStuff("multiset gestreut ", m, &gestreut);
std::set<int> s{};
timeStuff("set alleGleich ", s, &alleGleich);
timeStuff("set gestreut ", s, &gestreut);
std::unordered_multiset<int> um{};
timeStuff("unordered_multiset alleGleich ", um, &alleGleich);
timeStuff("unordered_multiset gestreut ", um, &gestreut);
std::unordered_multiset<int,BadHash> umb{};
timeStuff("unordered_multiset alleGleich badHash", umb, &alleGleich);
timeStuff("unordered_multiset gestreut badHash", umb, &gestreut);
}
Listing 24.76: Doppelt so viele Elemente bei schlechter Hashfunktion heißt viermal länger.
Book listing lst-0792-book.cpp:
// https://godbolt.org/z/osdTM7vbx
#include <unordered_set> // unordered_set, unordered_multiset
#include <iostream>
#include <string>
#include <chrono> // Zeitmessung
using std::cout;
using namespace std::chrono;
long long millisSeit(steady_clock::time_point start) {
return duration_cast<milliseconds>(steady_clock::now()-start)
.count();
}
struct BadHash { // die schlechtestmögliche Hashfunktion als Funktor
size_t operator()(int) const { return 1uz; }
};
void timeStuff(size_t iters) {
std::unordered_multiset<int,BadHash> data{};
cout << iters << "...";
auto start = steady_clock::now();
for(size_t idx=0; idx<iters; ++idx) {
data.insert( (int)idx );
}
cout << " " << millisSeit(start) << " ms" << std::endl;
}
constexpr size_t LIMIT = 20'000;
int main() {
size_t iters = 100;
while(iters < LIMIT) {
timeStuff(iters);
iters *= 2; // verdoppeln
}
}
Godbolt Listing lst-0792-godb.cpp, https://godbolt.org/z/osdTM7vbx:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/osdTM7vbx
#include <unordered_set> // unordered_set, unordered_multiset
#include <iostream>
#include <string>
#include <chrono> // Zeitmessung
using std::cout;
using namespace std::chrono;
long long millisSeit(steady_clock::time_point start) {
return duration_cast<milliseconds>(steady_clock::now()-start)
.count();
}
struct BadHash { // die schlechtestmögliche Hashfunktion als Funktor
size_t operator()(int) const { return 1uz; }
};
void timeStuff(size_t iters) {
std::unordered_multiset<int,BadHash> data{};
cout << iters << "...";
auto start = steady_clock::now();
for(size_t idx=0; idx<iters; ++idx) {
data.insert( (int)idx );
}
cout << " " << millisSeit(start) << " ms" << std::endl;
}
constexpr size_t LIMIT = 20'000;
int main() {
size_t iters = 100;
while(iters < LIMIT) {
timeStuff(iters);
iters *= 2; // verdoppeln
}
}
Listing 24.77: Dies ist die Schablone für die Beispiellistings zu »unordered_set«.
Book listing lst-0793-book.cpp:
// https://godbolt.org/z/xv6vrcsY6
#include <unordered_set>
#include <iostream>
using std::unordered_set; using std::cout; using std::ostream;
template<typename Elem, typename Cmp>
ostream& operator<<=(ostream&os, const unordered_set<Elem,Cmp>&data){
for(auto &e : data) {
os << e << ' ';
}
return os << '\n'; // '<<=' statt '<<' für Zeilenumbruch
}
int main() {
// Beispielcode hier
}
Godbolt Listing lst-0793-godb.cpp, https://godbolt.org/z/xv6vrcsY6:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/xv6vrcsY6
#include <unordered_set>
#include <iostream>
using std::unordered_set; using std::cout; using std::ostream;
template<typename Elem, typename Cmp>
ostream& operator<<=(ostream&os, const unordered_set<Elem,Cmp>&data){
for(auto &e : data) {
os << e << ' ';
}
return os << '\n'; // '<<=' statt '<<' für Zeilenumbruch
}
int main() {
// Beispielcode hier
}
Listing 24.78: Ein »unordered_set« mit eigenem Vergleich und Hashfunktion
Book listing lst-0794-book.cpp:
// https://godbolt.org/z/MWrY1cznd
#include <unordered_set>
#include <iostream>
#include <vector>
#include <string>
using std::string; using std::unordered_set; using std::cout;
struct Word {
string word_;
size_t row_;
Word(const string &word, size_t row)
: word_{word}, row_{row} {}
friend bool operator==(const Word& a, const Word &b)
{ return a.word_ == b.word_; } // ignoriert row
};
namespace std {
template<> struct hash<Word> { // ignoriert row
std::hash<string> stringHash;
std::size_t operator()(const Word &w) const {
return stringHash(w.word_);
}
}; }
struct ExactWordHash { // bezieht row mit ein
std::hash<string> sHash;
std::hash<size_t> iHash;
bool operator()(const Word& a) const {
return sHash(a.word_) ^ iHash(a.row_);
}
};
struct ExactWordEqual { // bezieht row mit ein
bool operator()(const Word& a, const Word &b) const {
return std::tie(a.word_, a.row_) == std::tie(b.word_, b.row_);
}
};
int main() {
std::vector input {
Word{"eine",0}, Word{"Rose",0},
Word{"ist",1}, Word{"eine",1}, Word{"Rose",1},
Word{"ist",2}, Word{"eine",2}, Word{"Rose",2}, };
// Überladungen nutzen
unordered_set<Word> words( input.begin(), input.end() );
cout << words.size() << '\n'; // Ausgabe: 3
// Eigene Funktoren nutzen
unordered_set<Word,ExactWordHash,ExactWordEqual> poem(
input.begin(), input.end() );
cout << poem.size() << '\n'; // Ausgabe: 8
// Hash als Lambda
auto h = [](const auto &a) { return std::hash<string>{}(a.word_); };
unordered_set<Word,decltype(h)> rose(input.begin(), input.end(), 10, h);
cout << rose.size() << '\n'; // Ausgabe: 3
}
Godbolt Listing lst-0794-godb.cpp, https://godbolt.org/z/MWrY1cznd:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/MWrY1cznd
#include <unordered_set>
#include <iostream>
#include <vector>
#include <string>
using std::string; using std::unordered_set; using std::cout;
struct Word {
string word_;
size_t row_;
Word(const string &word, size_t row)
: word_{word}, row_{row} {}
friend bool operator==(const Word& a, const Word &b)
{ return a.word_ == b.word_; } // ignoriert row
};
namespace std {
template<> struct hash<Word> { // ignoriert row
std::hash<string> stringHash;
std::size_t operator()(const Word &w) const {
return stringHash(w.word_);
}
}; }
struct ExactWordHash { // bezieht row mit ein
std::hash<string> sHash;
std::hash<size_t> iHash;
bool operator()(const Word& a) const {
return sHash(a.word_) ^ iHash(a.row_);
}
};
struct ExactWordEqual { // bezieht row mit ein
bool operator()(const Word& a, const Word &b) const {
return std::tie(a.word_, a.row_) == std::tie(b.word_, b.row_);
}
};
int main() {
std::vector input {
Word{"eine",0}, Word{"Rose",0},
Word{"ist",1}, Word{"eine",1}, Word{"Rose",1},
Word{"ist",2}, Word{"eine",2}, Word{"Rose",2}, };
// Überladungen nutzen
unordered_set<Word> words( input.begin(), input.end() );
cout << words.size() << '\n'; // Ausgabe: 3
// Eigene Funktoren nutzen
unordered_set<Word,ExactWordHash,ExactWordEqual> poem(
input.begin(), input.end() );
cout << poem.size() << '\n'; // Ausgabe: 8
// Hash als Lambda
auto h = [](const auto &a) { return std::hash<string>{}(a.word_); };
unordered_set<Word,decltype(h)> rose(input.begin(), input.end(), 10, h);
cout << rose.size() << '\n'; // Ausgabe: 3
}
Listing 24.79: Dies sind die Möglichkeiten, ein »unordered_set« zu initialisieren.
Book listing lst-0796-book.cpp:
// https://godbolt.org/z/WeMr9ePdh
#include <set>
template<typename Key>
std::set<Key> sorted(const unordered_set<Key> &data)
{ return std::set<Key>(data.begin(), data.end()); }
// …
// ohne Argumente
unordered_set<int> leer{};
cout <<= leer; // Ausgabe:
// Initialisierungsliste
unordered_set daten{1,1,2,2,3,3,4,4,5,5};// doppelte werden nicht übernommen
cout <<= daten; // Ausgabe in etwa: 5 4 3 2 1
// Kopie
unordered_set kopie(daten);
cout <<= kopie; // Ausgabe in etwa: 5 4 3 2 1
// Bereich
auto so1 = sorted(daten);
unordered_set bereich(std::next(so1.begin()), std::prev(so1.end()));
cout <<= bereich; // Ausgabe in etwa: 2 3 4
Godbolt Listing lst-0796-godb.cpp, https://godbolt.org/z/WeMr9ePdh:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/WeMr9ePdh
#include <set>
template<typename Key>
std::set<Key> sorted(const unordered_set<Key> &data)
{ return std::set<Key>(data.begin(), data.end()); }
// …
// ohne Argumente
unordered_set<int> leer{};
cout <<= leer; // Ausgabe:
// Initialisierungsliste
unordered_set daten{1,1,2,2,3,3,4,4,5,5};// doppelte werden nicht übernommen
cout <<= daten; // Ausgabe in etwa: 5 4 3 2 1
// Kopie
unordered_set kopie(daten);
cout <<= kopie; // Ausgabe in etwa: 5 4 3 2 1
// Bereich
auto so1 = sorted(daten);
unordered_set bereich(std::next(so1.begin()), std::prev(so1.end()));
cout <<= bereich; // Ausgabe in etwa: 2 3 4
Listing 24.80: Einfügen in ein »unordered_set«
Book listing lst-0797-book.cpp:
// https://godbolt.org/z/KEb55ds4z
unordered_set<int> data;
auto res1 = data.insert( 5 ); // Einfügen per Kopie
if(res1.second) cout << "ja, 5 nun drin\n"; // das klappt
auto res2 = data.emplace( 5 ); // Einfügen vor Ort
if(res2.second) cout << "zweite 5 nun drin\n"; // das klappt nicht
auto res3 = data.insert(res1.first, 6 ); // mit Positionshinweis
// res3 ist nur ein iterator ohne bool
cout << *res3 << '\n'; // auf jeden Fall eine 6
Godbolt Listing lst-0797-godb.cpp, https://godbolt.org/z/KEb55ds4z:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/KEb55ds4z
unordered_set<int> data;
auto res1 = data.insert( 5 ); // Einfügen per Kopie
if(res1.second) cout << "ja, 5 nun drin\n"; // das klappt
auto res2 = data.emplace( 5 ); // Einfügen vor Ort
if(res2.second) cout << "zweite 5 nun drin\n"; // das klappt nicht
auto res3 = data.insert(res1.first, 6 ); // mit Positionshinweis
// res3 ist nur ein iterator ohne bool
cout << *res3 << '\n'; // auf jeden Fall eine 6
Listing 24.81: Löschen erhält die Reihenfolge der restlichen Elemente.
Book listing lst-0798-book.cpp:
// https://godbolt.org/z/1s41eaWjx
unordered_set nums{ 1,2,3,4,5,6,7,8,9,10 };
cout <<= nums; // Ausgabe ähnlich: 9 1 2 3 4 5 6 7 8 10
auto it = nums.begin();
while(it != nums.end()) {
if(*it % 2 == 0) { // gerade Zahl?
it = nums.erase(it); // Restelemente verändern nicht Reihenfolge
} else {
++it;
}
}
cout <<= nums; // Ausgabe ähnlich: 9 1 3 5 7
Godbolt Listing lst-0798-godb.cpp, https://godbolt.org/z/1s41eaWjx:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/1s41eaWjx
unordered_set nums{ 1,2,3,4,5,6,7,8,9,10 };
cout <<= nums; // Ausgabe ähnlich: 9 1 2 3 4 5 6 7 8 10
auto it = nums.begin();
while(it != nums.end()) {
if(*it % 2 == 0) { // gerade Zahl?
it = nums.erase(it); // Restelemente verändern nicht Reihenfolge
} else {
++it;
}
}
cout <<= nums; // Ausgabe ähnlich: 9 1 3 5 7
Listing 24.82: Sie können eimerweise auf »unordered_set« zugreifen.
Book listing lst-0799-book.cpp:
// https://godbolt.org/z/TTbY8YbG9
// Befüllen mit 100 Werten
unordered_set<int> d{};
d.rehash(10); // versuche, 10 Eimer zu haben
d.max_load_factor(100.0); // 100 Elemente pro Eimer sind okay
cout << "Eimer Anzahl: " << d.bucket_count() << '\n';
for(int x : std::ranges::iota_view{0,100}) { // C++20 iota(): 0,1,2,…,99
d.insert(x);
}
// ausgeben
for(int b = d.bucket_count()-1; b>=0; --b) {
cout << "Eimer "<<b<<":";
for(auto it=d.begin(b); it!=d.end(b); ++it)
cout << *it << ' ';
cout << '\n';
}
Godbolt Listing lst-0799-godb.cpp, https://godbolt.org/z/TTbY8YbG9:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/TTbY8YbG9
// Befüllen mit 100 Werten
unordered_set<int> d{};
d.rehash(10); // versuche, 10 Eimer zu haben
d.max_load_factor(100.0); // 100 Elemente pro Eimer sind okay
cout << "Eimer Anzahl: " << d.bucket_count() << '\n';
for(int x : std::ranges::iota_view{0,100}) { // C++20 iota(): 0,1,2,…,99
d.insert(x);
}
// ausgeben
for(int b = d.bucket_count()-1; b>=0; --b) {
cout << "Eimer "<<b<<":";
for(auto it=d.begin(b); it!=d.end(b); ++it)
cout << *it << ' ';
cout << '\n';
}
Listing 24.83: Dies ist die Schablone für die Beispiellistings zu »unordered_map«.
Book listing lst-0800-book.cpp:
// https://godbolt.org/z/ffashhsK1
#include <unordered_map>
#include <iostream>
using std::unordered_map; using std::cout;
template<typename K, typename T>
std::ostream& operator<<=(std::ostream&os, const unordered_map<K,T>&data) {
for(auto &e : data) {
os << e.first << ":" << e.second << ' ';
}
return os << '\n'; // bei operator<<= mit Zeilenumbruch
}
int main() {
// Beispielcode hier
}
Godbolt Listing lst-0800-godb.cpp, https://godbolt.org/z/ffashhsK1:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/ffashhsK1
#include <unordered_map>
#include <iostream>
using std::unordered_map; using std::cout;
template<typename K, typename T>
std::ostream& operator<<=(std::ostream&os, const unordered_map<K,T>&data) {
for(auto &e : data) {
os << e.first << ":" << e.second << ' ';
}
return os << '\n'; // bei operator<<= mit Zeilenumbruch
}
int main() {
// Beispielcode hier
}
Listing 24.84: Ein eigener Datentyp als Schlüssel in einer »unordered_map«
Book listing lst-0801-book.cpp:
// https://godbolt.org/z/Ka3czrn54
#include <unordered_map>
#include <iostream>
#include <string>
using std::string; using std::unordered_map; using std::cout;
struct Stadt {
string name_;
explicit Stadt(const string &name) : name_{name} {}
auto operator<=>(const Stadt &b) const = default;
};
struct StadtHash {
std::hash<string> sHash;
size_t operator()(const Stadt& a) const {
return sHash(a.name_);
}
};
int main() {
unordered_map<Stadt,string,StadtHash> abk{
{Stadt{"Bielefeld"}, "BI"},
{Stadt{"Jetzendorf"}, "JE"},
{Stadt{"Tharandt"}, "TH"},
};
cout << abk[Stadt{"Bielefeld"}] << '\n'; // Ausgabe: BI
}
Godbolt Listing lst-0801-godb.cpp, https://godbolt.org/z/Ka3czrn54:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Ka3czrn54
#include <unordered_map>
#include <iostream>
#include <string>
using std::string; using std::unordered_map; using std::cout;
struct Stadt {
string name_;
explicit Stadt(const string &name) : name_{name} {}
auto operator<=>(const Stadt &b) const = default;
};
struct StadtHash {
std::hash<string> sHash;
size_t operator()(const Stadt& a) const {
return sHash(a.name_);
}
};
int main() {
unordered_map<Stadt,string,StadtHash> abk{
{Stadt{"Bielefeld"}, "BI"},
{Stadt{"Jetzendorf"}, "JE"},
{Stadt{"Tharandt"}, "TH"},
};
cout << abk[Stadt{"Bielefeld"}] << '\n'; // Ausgabe: BI
}
Listing 24.85: Sie können auch nur einen Teil Ihres Objekts als Schlüssel verwenden.
Book listing lst-0802-book.cpp:
// https://godbolt.org/z/eTYqbedqK
#include <unordered_set> // unordered_multiset
#include <iostream>
#include <string>
using std::string; using std::unordered_multiset; using std::cout;
struct Stadt {
string name_;
explicit Stadt(const string &name) : name_{name} {}
auto operator<=>(const Stadt &b) const = default;
};
struct Eintrag { string stadt_; int plz_; };
struct EqEintrag {
bool operator()(const Eintrag&a, const Eintrag&b) const {
return a.stadt_==b.stadt_;
}
};
struct HashEintrag {
std::hash<string> sHash;
size_t operator()(const Eintrag& a) const {
return sHash(a.stadt_);
}
};
int main() {
unordered_multiset<Eintrag,HashEintrag,EqEintrag> verzeichnis{
{Eintrag{"Bielefeld", 33615}},
{Eintrag{"Bielefeld", 33617}},
{Eintrag{"Bielefeld", 33621}},
{Eintrag{"Berlin", 10032}},
{Eintrag{"Berlin", 10027}},
};
const Eintrag such{"Bielefeld", 0}; // plz spielt bei Suche keine Rolle
cout<<"Bielefeld hat "<<verzeichnis.count(such)<<" Postleitzahlen.\n";
cout<<"Die Postleitzahlen von Bielefeld sind:\n";
auto [wo, bis] = verzeichnis.equal_range(such);
while(wo != bis) {
cout << " " << wo->plz_ << '\n';
++wo;
}
}
Godbolt Listing lst-0802-godb.cpp, https://godbolt.org/z/eTYqbedqK:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/eTYqbedqK
#include <unordered_set> // unordered_multiset
#include <iostream>
#include <string>
using std::string; using std::unordered_multiset; using std::cout;
struct Stadt {
string name_;
explicit Stadt(const string &name) : name_{name} {}
auto operator<=>(const Stadt &b) const = default;
};
struct Eintrag { string stadt_; int plz_; };
struct EqEintrag {
bool operator()(const Eintrag&a, const Eintrag&b) const {
return a.stadt_==b.stadt_;
}
};
struct HashEintrag {
std::hash<string> sHash;
size_t operator()(const Eintrag& a) const {
return sHash(a.stadt_);
}
};
int main() {
unordered_multiset<Eintrag,HashEintrag,EqEintrag> verzeichnis{
{Eintrag{"Bielefeld", 33615}},
{Eintrag{"Bielefeld", 33617}},
{Eintrag{"Bielefeld", 33621}},
{Eintrag{"Berlin", 10032}},
{Eintrag{"Berlin", 10027}},
};
const Eintrag such{"Bielefeld", 0}; // plz spielt bei Suche keine Rolle
cout<<"Bielefeld hat "<<verzeichnis.count(such)<<" Postleitzahlen.\n";
cout<<"Die Postleitzahlen von Bielefeld sind:\n";
auto [wo, bis] = verzeichnis.equal_range(such);
while(wo != bis) {
cout << " " << wo->plz_ << '\n';
++wo;
}
}
GodboltId:9szMGYK9v
Book listing lst-0804-book.cpp:
// https://godbolt.org/z/9szMGYK9v
struct EqEintrag {
bool operator()(const Eintrag&a, const Eintrag&b) const {
return a.stadt_==b.stadt_;
}
};
struct HashEintrag {
std::hash<string> sHash;
std::hash<int> iHash;
size_t operator()(const Eintrag& a) const {
return sHash(a.stadt_) ^ iHash(a.plz_); // (ERR) zu viele Elemente
}
};
Godbolt Listing lst-0804-godb.cpp, https://godbolt.org/z/9szMGYK9v:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/9szMGYK9v
struct EqEintrag {
bool operator()(const Eintrag&a, const Eintrag&b) const {
return a.stadt_==b.stadt_;
}
};
struct HashEintrag {
std::hash<string> sHash;
std::hash<int> iHash;
size_t operator()(const Eintrag& a) const {
return sHash(a.stadt_) ^ iHash(a.plz_); // (ERR) zu viele Elemente
}
};
Listing 24.86: Dies sind die Möglichkeiten, ein »unordered_multiset« zu initialisieren.
Book listing lst-0805-book.cpp:
// https://godbolt.org/z/qnove9h8o
#include <unordered_set> // unordered_multiset
#include <vector>
#include <iostream>
using std::unordered_multiset; using std::cout; using std::ostream;
template<typename Elem>
ostream& operator<<=(ostream&os, const unordered_multiset<Elem>&data) {
for(auto &e : data) { os << e << ' '; } return os << '\n'; }
int main() {
// ohne Argumente
unordered_multiset<int> leer(1000); // anfängliche Größe der Hashtabelle
cout <<= leer; // Ausgabe:
// Initialisierungsliste; doppelte werden übernommen:
unordered_multiset daten{ 1,1,2,2,3,3,4,4,5,5 };
cout <<= daten; // Ausgabe in etwa: 5 5 4 4 3 3 2 2 1 1
// Kopie
unordered_multiset kopie(daten);
cout <<= kopie; // Ausgabe in etwa: 5 5 4 4 3 3 2 2 1 1
// Bereich
std::vector in{1,2,3,10,20,30,10,20,30,1,2,3};
unordered_multiset bereich(in.begin()+3, in.end()-3);
cout <<= bereich; // Ausgabe in etwa: 30 30 20 20 10 10
}
Godbolt Listing lst-0805-godb.cpp, https://godbolt.org/z/qnove9h8o:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/qnove9h8o
#include <unordered_set> // unordered_multiset
#include <vector>
#include <iostream>
using std::unordered_multiset; using std::cout; using std::ostream;
template<typename Elem>
ostream& operator<<=(ostream&os, const unordered_multiset<Elem>&data) {
for(auto &e : data) { os << e << ' '; } return os << '\n'; }
int main() {
// ohne Argumente
unordered_multiset<int> leer(1000); // anfängliche Größe der Hashtabelle
cout <<= leer; // Ausgabe:
// Initialisierungsliste; doppelte werden übernommen:
unordered_multiset daten{ 1,1,2,2,3,3,4,4,5,5 };
cout <<= daten; // Ausgabe in etwa: 5 5 4 4 3 3 2 2 1 1
// Kopie
unordered_multiset kopie(daten);
cout <<= kopie; // Ausgabe in etwa: 5 5 4 4 3 3 2 2 1 1
// Bereich
std::vector in{1,2,3,10,20,30,10,20,30,1,2,3};
unordered_multiset bereich(in.begin()+3, in.end()-3);
cout <<= bereich; // Ausgabe in etwa: 30 30 20 20 10 10
}
Listing 24.87: Bei den »multi«-Varianten ergibt »count« richtig Sinn.
Book listing lst-0806-book.cpp:
// https://godbolt.org/z/a8cGxr9s9
#include <unordered_set> // unordered_multiset
#include <iostream>
#include <string>
using std::unordered_multiset; using std::cout; using std::string;
int main() {
const string in = "Keines meiner beiden Beine zeigt einen Schein.";
unordered_multiset<int> cs(in.begin(), in.end()); // string als Container
cout << cs.count( 'e' ) << " Mal e\n"; // Ausgabe: 10 Mal e
}
Godbolt Listing lst-0806-godb.cpp, https://godbolt.org/z/a8cGxr9s9:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/a8cGxr9s9
#include <unordered_set> // unordered_multiset
#include <iostream>
#include <string>
using std::unordered_multiset; using std::cout; using std::string;
int main() {
const string in = "Keines meiner beiden Beine zeigt einen Schein.";
unordered_multiset<int> cs(in.begin(), in.end()); // string als Container
cout << cs.count( 'e' ) << " Mal e\n"; // Ausgabe: 10 Mal e
}
Listing 24.88: Adapter funktionieren mit wechselbaren Implementierungen.
Book listing lst-0807-book.cpp:
// https://godbolt.org/z/qaKv6Tebf
#include <stack>
void run(auto data) { /* ... */ } // C++20, abgekürztes Funktionstemplate
run(stack<int>{}); // Default: nutzt vector<int>
run(stack<int,vector<int>>{}); // wie der Default
run(stack<int,list<int>>{}); // nutzt list<int>
Godbolt Listing lst-0807-godb.cpp, https://godbolt.org/z/qaKv6Tebf:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/qaKv6Tebf
#include <stack>
void run(auto data) { /* ... */ } // C++20, abgekürztes Funktionstemplate
run(stack<int>{}); // Default: nutzt vector<int>
run(stack<int,vector<int>>{}); // wie der Default
run(stack<int,list<int>>{}); // nutzt list<int>
Listing 24.89: »string« eignet sich besser für Texte als »vector«.
Book listing lst-0808-book.cpp:
// https://godbolt.org/z/6sYGnqnTj
#include <vector>
#include <string>
#include <iostream>
#include <string_view>
using std::string; using std::string_view; using std::vector; using std::cout;
int get_len(string_view str) { return str.size(); } // string_view als Parameter
int main() {
string s1 = "Hallo"; // einfach mit Stringliteral
string s2{'H','a','l','l','o'}; // oder mit Liste von char
using namespace std::literals; // für ""s-Suffix und ""sv-Suffix
auto s3 = "Hallo"s; // noch einfacher mit echtem Stringliteral
vector<char> v1{"Hallo"}; // (ERR) kein vector mit Stringliteral
vector<char> v2{'H','a','l','l','o'}; // Liste von char ist okay
cout << s1 << s2 << s3 << '\n'; // Ausgabe von string geht
cout << v1 << v2 << '\n'; // (ERR) vector hat keine Ausgabe
const auto str = "String"s; // Stringliteral
const auto strv = "String-View"sv; // String-View-Literal
cout << "Laenge von 'str' ist " << get_len(str) << '\n'; // Ausgabe: … 6
cout << "Laenge von 'strv' ist " << get_len(strv) << '\n'; // Ausgabe: … 11
}
Godbolt Listing lst-0808-godb.cpp, https://godbolt.org/z/6sYGnqnTj:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/6sYGnqnTj
#include <vector>
#include <string>
#include <iostream>
#include <string_view>
using std::string; using std::string_view; using std::vector; using std::cout;
int get_len(string_view str) { return str.size(); } // string_view als Parameter
int main() {
string s1 = "Hallo"; // einfach mit Stringliteral
string s2{'H','a','l','l','o'}; // oder mit Liste von char
using namespace std::literals; // für ""s-Suffix und ""sv-Suffix
auto s3 = "Hallo"s; // noch einfacher mit echtem Stringliteral
vector<char> v1{"Hallo"}; // (ERR) kein vector mit Stringliteral
vector<char> v2{'H','a','l','l','o'}; // Liste von char ist okay
cout << s1 << s2 << s3 << '\n'; // Ausgabe von string geht
cout << v1 << v2 << '\n'; // (ERR) vector hat keine Ausgabe
const auto str = "String"s; // Stringliteral
const auto strv = "String-View"sv; // String-View-Literal
cout << "Laenge von 'str' ist " << get_len(str) << '\n'; // Ausgabe: … 6
cout << "Laenge von 'strv' ist " << get_len(strv) << '\n'; // Ausgabe: … 11
}
Listing 24.90: »bitset« im Beispiel
Book listing lst-0809-book.cpp:
// https://godbolt.org/z/jrGdT6665
#include <bitset>
#include <iostream>
using std::cout;
int main() {
std::bitset<8> bits{}; // 8 Bit dicht gepackt
bits.set(4); // 5. Bit auf 1
cout << bits << '\n'; // 00010000
bits.flip(); // alle Bits invertieren
cout << bits << '\n'; // 11101111
bits.set(); // alle Bits auf 1
bits.flip(1); // 2. Bit invertieren
std::cout << bits << '\n'; // 11111101
bits.reset(); // alle Bits auf 0
bits.set(4); // 5. Bit auf 1
cout << bits << '\n'; // 00010000
bits.flip(); // alle Bits invertieren
cout << bits << '\n'; // 11101111
bits.set(); // alle Bits auf 1
bits.flip(1); // 2. Bit invertieren
bits.flip(6); // 7. Bit invertieren
cout << bits << '\n'; // 10111101
// Verknüpfungen
std::bitset<8> zack("....####", 8, '.', '#');
cout << zack << '\n'; // 00001111
cout << (bits & zack) << '\n'; // 00001101
cout << (bits | zack) << '\n'; // 10111111
cout << (bits ^ zack) << '\n'; // 10110010
// andere Integertypen
std::bitset<64> b(0x123456789abcdef0LL);
cout << b << '\n';
// 0001001000110100010101100111100010011010101111001101111011110000
cout << std::hex << b.to_ullong() << '\n'; // umwandeln
// 123456789abcdef0
}
Godbolt Listing lst-0809-godb.cpp, https://godbolt.org/z/jrGdT6665:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/jrGdT6665
#include <bitset>
#include <iostream>
using std::cout;
int main() {
std::bitset<8> bits{}; // 8 Bit dicht gepackt
bits.set(4); // 5. Bit auf 1
cout << bits << '\n'; // 00010000
bits.flip(); // alle Bits invertieren
cout << bits << '\n'; // 11101111
bits.set(); // alle Bits auf 1
bits.flip(1); // 2. Bit invertieren
std::cout << bits << '\n'; // 11111101
bits.reset(); // alle Bits auf 0
bits.set(4); // 5. Bit auf 1
cout << bits << '\n'; // 00010000
bits.flip(); // alle Bits invertieren
cout << bits << '\n'; // 11101111
bits.set(); // alle Bits auf 1
bits.flip(1); // 2. Bit invertieren
bits.flip(6); // 7. Bit invertieren
cout << bits << '\n'; // 10111101
// Verknüpfungen
std::bitset<8> zack("....####", 8, '.', '#');
cout << zack << '\n'; // 00001111
cout << (bits & zack) << '\n'; // 00001101
cout << (bits | zack) << '\n'; // 10111111
cout << (bits ^ zack) << '\n'; // 10110010
// andere Integertypen
std::bitset<64> b(0x123456789abcdef0LL);
cout << b << '\n';
// 0001001000110100010101100111100010011010101111001101111011110000
cout << std::hex << b.to_ullong() << '\n'; // umwandeln
// 123456789abcdef0
}
GodboltId:KPP16bdK9
Book listing lst-0810-book.cpp:
// https://godbolt.org/z/KPP16bdK9
#include <iostream>
#include <valarray>
using std::ostream; using std::valarray;
ostream& operator<<(ostream&os, const valarray<double>&vs) {
os << "[";
for(auto&v : vs) os << v << " ";
return os << "]";
}
int main() {
valarray a{ 1.0, 2.0, 3.0, 4.0 }; // valarray<double>
valarray b{ 2.0, 4.0, 6.0, 8.0 };
valarray c{ 2.5, 1.75, 0.5, 0.125 };
valarray<double> x = ( a + b ) * c;
std::cout << "x: " << x << "\n"; // Ausgabe: [7.5 10.5 4.5 1.5 ]
auto y = ( a + b ) / 2; // y ist nicht unbedingt ein valarray!
std::cout << "y: " << y << "\n"; // Ausgabe: [1.5 3 4.5 6 ]
}
Godbolt Listing lst-0810-godb.cpp, https://godbolt.org/z/KPP16bdK9:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/KPP16bdK9
#include <iostream>
#include <valarray>
using std::ostream; using std::valarray;
ostream& operator<<(ostream&os, const valarray<double>&vs) {
os << "[";
for(auto&v : vs) os << v << " ";
return os << "]";
}
int main() {
valarray a{ 1.0, 2.0, 3.0, 4.0 }; // valarray<double>
valarray b{ 2.0, 4.0, 6.0, 8.0 };
valarray c{ 2.5, 1.75, 0.5, 0.125 };
valarray<double> x = ( a + b ) * c;
std::cout << "x: " << x << "\n"; // Ausgabe: [7.5 10.5 4.5 1.5 ]
auto y = ( a + b ) / 2; // y ist nicht unbedingt ein valarray!
std::cout << "y: " << y << "\n"; // Ausgabe: [1.5 3 4.5 6 ]
}
GodboltId:r11584Wef
Book listing lst-0811-book.cpp:
// https://godbolt.org/z/r11584Wef
#include <valarray>
#include <iostream>
using namespace std;
template<typename T>
ostream& operator<<=(ostream &os, const valarray<T>& a) { // '<<=' mit Newline
for(const auto &v : a) os << v << ' ';
return os << '\n';
}
int main() {
// … Beispielcode hier …
}
Godbolt Listing lst-0811-godb.cpp, https://godbolt.org/z/r11584Wef:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/r11584Wef
#include <valarray>
#include <iostream>
using namespace std;
template<typename T>
ostream& operator<<=(ostream &os, const valarray<T>& a) { // '<<=' mit Newline
for(const auto &v : a) os << v << ' ';
return os << '\n';
}
int main() {
// … Beispielcode hier …
}
GodboltId:WGazqoGc1
Book listing lst-0812-book.cpp:
// https://godbolt.org/z/WGazqoGc1
valarray<int> data; // zunächst Größe 0
cout << data.size() << "\n"; // Ausgabe: 0
data.resize(100); // vergrößert
cout << data.size() << "\n"; // Ausgabe: 100
valarray<int> data2(200); // Platz für 200 Werte
cout << data2.size() << "\n"; // Ausgabe: 200
valarray<int> dataC(5, 20); // zwanzig 5en, andersherum als bei vector
cout << dataC.size() <<": dataC[6]="<< dataC[6]<< "\n"; // Ausgabe: 20: dataC[6]=5
valarray dataD{ 2, 3, 5, 7, 11 }; // valarray<int>, Initialisierungsliste
cout << dataD.size() <<": dataD[3]=" <<dataD[3]<< "\n"; // Ausgabe: 5: dataD[3]=7
Godbolt Listing lst-0812-godb.cpp, https://godbolt.org/z/WGazqoGc1:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/WGazqoGc1
valarray<int> data; // zunächst Größe 0
cout << data.size() << "\n"; // Ausgabe: 0
data.resize(100); // vergrößert
cout << data.size() << "\n"; // Ausgabe: 100
valarray<int> data2(200); // Platz für 200 Werte
cout << data2.size() << "\n"; // Ausgabe: 200
valarray<int> dataC(5, 20); // zwanzig 5en, andersherum als bei vector
cout << dataC.size() <<": dataC[6]="<< dataC[6]<< "\n"; // Ausgabe: 20: dataC[6]=5
valarray dataD{ 2, 3, 5, 7, 11 }; // valarray<int>, Initialisierungsliste
cout << dataD.size() <<": dataD[3]=" <<dataD[3]<< "\n"; // Ausgabe: 5: dataD[3]=7
GodboltId:dd1q6GdYq
Book listing lst-0813-book.cpp:
// https://godbolt.org/z/dd1q6GdYq
valarray v { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
valarray<int> r1(v[slice(0, 4, 3)]); // Start bei 0, 4 Elemente, Schrittweite 3
cout <<= r1; // Ausgabe: 1 4 7 10
valarray<int> r2(v[v > 6]); // adressiert per valarray<bool>
cout <<= r2; // Ausgabe: 7 8 9 10 11 12
const valarray<size_t> indirekt{ 2, 2, 3, 6 }; // doppelte erlaubt
valarray<int> r5(v[indirekt]); // adressiert per valarray<size_t>
cout <<= r5; // Ausgabe: 3 3 4 7
Godbolt Listing lst-0813-godb.cpp, https://godbolt.org/z/dd1q6GdYq:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/dd1q6GdYq
valarray v { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
valarray<int> r1(v[slice(0, 4, 3)]); // Start bei 0, 4 Elemente, Schrittweite 3
cout <<= r1; // Ausgabe: 1 4 7 10
valarray<int> r2(v[v > 6]); // adressiert per valarray<bool>
cout <<= r2; // Ausgabe: 7 8 9 10 11 12
const valarray<size_t> indirekt{ 2, 2, 3, 6 }; // doppelte erlaubt
valarray<int> r5(v[indirekt]); // adressiert per valarray<size_t>
cout <<= r5; // Ausgabe: 3 3 4 7
GodboltId:6z6d71Ka4
Book listing lst-0814-book.cpp:
// https://godbolt.org/z/6z6d71Ka4
valarray<int> v {
1, 2, 3,
4, 5, 6,
7, 8, 9,
10, 11, 12 };
v[slice(0, 4, 3)] *= valarray<int>(v[slice(0, 4, 3)]); // erste Spalte quadrieren
cout <<= v; // Ausgabe: 1 2 3 16 5 6 49 8 9 100 11 12
v[slice(0, 4, 3)] = valarray<int>{1, 4, 7, 10}; // wiederherstellen
valarray<int> r3(v[gslice(0, {2, 3}, {6,2})]); // 2-D-Schnitt vom 3-D-Würfel
cout <<= r3; // Ausgabe: 1 3 5 7 9 11
valarray<char> text("jetzt gehts erst los", 20);
valarray<char> caps("JGEL", 4);
valarray<size_t> idx{ 0, 6, 12, 17 }; // Indexe in text
text[idx] = caps; // indirekt zuweisen
cout <<= text; // Ausgabe: Jetzt Gehts Erst Los
Godbolt Listing lst-0814-godb.cpp, https://godbolt.org/z/6z6d71Ka4:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/6z6d71Ka4
valarray<int> v {
1, 2, 3,
4, 5, 6,
7, 8, 9,
10, 11, 12 };
v[slice(0, 4, 3)] *= valarray<int>(v[slice(0, 4, 3)]); // erste Spalte quadrieren
cout <<= v; // Ausgabe: 1 2 3 16 5 6 49 8 9 100 11 12
v[slice(0, 4, 3)] = valarray<int>{1, 4, 7, 10}; // wiederherstellen
valarray<int> r3(v[gslice(0, {2, 3}, {6,2})]); // 2-D-Schnitt vom 3-D-Würfel
cout <<= r3; // Ausgabe: 1 3 5 7 9 11
valarray<char> text("jetzt gehts erst los", 20);
valarray<char> caps("JGEL", 4);
valarray<size_t> idx{ 0, 6, 12, 17 }; // Indexe in text
text[idx] = caps; // indirekt zuweisen
cout <<= text; // Ausgabe: Jetzt Gehts Erst Los
GodboltId:jr1chqbze
Book listing lst-0815-book.cpp:
// https://godbolt.org/z/jr1chqbze
#include <iostream>
#include <iomanip> // setw
#include <valarray>
using namespace std;
/* Matrix drucken */
template<class T>
void printMatrix(ostream&os, const valarray<T>& a, size_t n) {
for(size_t i = 0; i < (n*n); ++i) {
os << setw(3) << a[i]; // Wert drucken
os << ((i+1)%n ? ' ' : '\n'); // nächste Zeile?
}
}
/* Matrix-Kreuzprodukt */
template<class T>
valarray<T> matmult(
const valarray<T>& a, size_t arows, size_t acols,
const valarray<T>& b, size_t brows, size_t bcols)
{
/* Bedingung: acols==brows */
valarray<T> result(arows * bcols);
for(size_t i = 0; i < arows; ++i) {
for(size_t j = 0; j < bcols; ++j) {
auto row = a[slice(acols*i, acols, 1)]; // Zeile
auto col = b[slice(j, brows, bcols)]; // Spalte
result[i*bcols+j] = (row*col).sum(); // Kreuzprodukt Zeile a[i] und
// Spalte b[j]
}
}
return result;
}
int main() {
constexpr int n = 3;
valarray ma{1,0,-1, 2,2,-3, 3,4,0}; // 3 x 3-Matrix
valarray mb{3,4,-1, 1,-3,0, -1,1,2}; // 3 x 3-Matrix
printMatrix(cout, ma, n);
cout << " -mal-\n ";
printMatrix(cout, mb, n);
cout << " -ergibt-:\n ";
valarray<int> mc = matmult(ma, n,n, mb, n,n);
printMatrix(cout, mc, n);
}
Godbolt Listing lst-0815-godb.cpp, https://godbolt.org/z/jr1chqbze:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/jr1chqbze
#include <iostream>
#include <iomanip> // setw
#include <valarray>
using namespace std;
/* Matrix drucken */
template<class T>
void printMatrix(ostream&os, const valarray<T>& a, size_t n) {
for(size_t i = 0; i < (n*n); ++i) {
os << setw(3) << a[i]; // Wert drucken
os << ((i+1)%n ? ' ' : '\n'); // nächste Zeile?
}
}
/* Matrix-Kreuzprodukt */
template<class T>
valarray<T> matmult(
const valarray<T>& a, size_t arows, size_t acols,
const valarray<T>& b, size_t brows, size_t bcols)
{
/* Bedingung: acols==brows */
valarray<T> result(arows * bcols);
for(size_t i = 0; i < arows; ++i) {
for(size_t j = 0; j < bcols; ++j) {
auto row = a[slice(acols*i, acols, 1)]; // Zeile
auto col = b[slice(j, brows, bcols)]; // Spalte
result[i*bcols+j] = (row*col).sum(); // Kreuzprodukt Zeile a[i] und
// Spalte b[j]
}
}
return result;
}
int main() {
constexpr int n = 3;
valarray ma{1,0,-1, 2,2,-3, 3,4,0}; // 3 x 3-Matrix
valarray mb{3,4,-1, 1,-3,0, -1,1,2}; // 3 x 3-Matrix
printMatrix(cout, ma, n);
cout << " -mal-\n ";
printMatrix(cout, mb, n);
cout << " -ergibt-:\n ";
valarray<int> mc = matmult(ma, n,n, mb, n,n);
printMatrix(cout, mc, n);
}
Listing 25.1: Mit dem Eingabevektor wird etwas gemacht, aber was?
Book listing lst-0816-book.cpp:
// https://godbolt.org/z/5czT3xoxc
std::vector v{0,1,3,5,7,9,2,4,6,8};
bool flag = true;
for(size_t i=1; (i <= v.size()) && flag; ++i) {
flag = false;
for(size_t j=0; (j < v.size()-1); ++j) {
if(v[j+1] < v[j]) {
std::swap(v[j+1], v[j]);
flag = true;
}
}
}
for(int i:v) std::cout << i << ' ';
Godbolt Listing lst-0816-godb.cpp, https://godbolt.org/z/5czT3xoxc:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/5czT3xoxc
std::vector v{0,1,3,5,7,9,2,4,6,8};
bool flag = true;
for(size_t i=1; (i <= v.size()) && flag; ++i) {
flag = false;
for(size_t j=0; (j < v.size()-1); ++j) {
if(v[j+1] < v[j]) {
std::swap(v[j+1], v[j]);
flag = true;
}
}
}
for(int i:v) std::cout << i << ' ';
Listing 25.2: Dieser Eingabevektor wird sortiert!
Book listing lst-0817-book.cpp:
// https://godbolt.org/z/EjT7nPPv7
std::vector v{0,1,3,5,7,9,2,4,6,8};
std::sort(v.begin(), v.end());
for(int i:v) std::cout << i << ' ';
std::cout << '\n';
// oder mit einer Range:
std::ranges::sort(v);
for(int i:v) std::cout << i << ' ';
std::cout << '\n';
Godbolt Listing lst-0817-godb.cpp, https://godbolt.org/z/EjT7nPPv7:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/EjT7nPPv7
std::vector v{0,1,3,5,7,9,2,4,6,8};
std::sort(v.begin(), v.end());
for(int i:v) std::cout << i << ' ';
std::cout << '\n';
// oder mit einer Range:
std::ranges::sort(v);
for(int i:v) std::cout << i << ' ';
std::cout << '\n';
Listing 25.3: Zusammenstecken von Funktionen
Book listing lst-0818-book.cpp:
// https://godbolt.org/z/9xrP8Ehvd
#include <algorithm>
#include <vector>
#include <iostream>
void sort_uniq(std::vector<int> &data) {
std::ranges::sort(data); // sortieren
auto to_delete = std::ranges::unique(data); // nach hinten verschieben
data.erase(to_delete.begin(), to_delete.end()); // tatsächlich löschen
}
int main() {
std::vector ns{1,5,2,3,9,2,2,2,2,1,5,2,2,3,1,1,2,2,1};
sort_uniq(ns);
std::ranges::for_each(ns, [](auto x) {
std::cout << x << ' '; });
std::cout << '\n'; // Ausgabe: 1 2 3 5 9
}
Godbolt Listing lst-0818-godb.cpp, https://godbolt.org/z/9xrP8Ehvd:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/9xrP8Ehvd
#include <algorithm>
#include <vector>
#include <iostream>
void sort_uniq(std::vector<int> &data) {
std::ranges::sort(data); // sortieren
auto to_delete = std::ranges::unique(data); // nach hinten verschieben
data.erase(to_delete.begin(), to_delete.end()); // tatsächlich löschen
}
int main() {
std::vector ns{1,5,2,3,9,2,2,2,2,1,5,2,2,3,1,1,2,2,1};
sort_uniq(ns);
std::ranges::for_each(ns, [](auto x) {
std::cout << x << ' '; });
std::cout << '\n'; // Ausgabe: 1 2 3 5 9
}
Listing 25.4: Algorithmen laufen parallel
Book listing lst-0819-book.cpp:
// https://godbolt.org/z/qcT9o7YfG
#include <algorithm> // find
#include <numeric> // reduce, accumulate
#include <execution> // std::execution
#include <iostream>
#include <chrono> // Zeitmessung
using namespace std::chrono;
long long millisSeit(steady_clock::time_point start) {
return duration_cast<milliseconds>(steady_clock::now()-start).count();
}
template <typename FUNC> void timeit(const char* title, FUNC func) {
auto start = steady_clock::now();
auto ret = func(); // ausführen
std::cout << title << ": " << millisSeit(start) << " ms" << std::endl;
}
int main() {
using namespace std::execution; // seq, par, par_unseq
using std::reduce; using std::accumulate; using std::find;
std::vector<double> v(600'000'000, 0.0); // 600 Millionen Elemente
for(auto&x:v) x = ::rand(); // mit Zufallswerten füllen
timeit("warmlaufen ", [&v] {
return reduce(seq, v.begin(), v.end(), 0.0);
});
timeit("accumulate ", [&v] {
return accumulate(v.begin(), v.end(), 0.0);
});
timeit("reduce, seq ", [&v] {
return reduce(seq, v.begin(), v.end(), 0.0);
});
timeit("reduce, par ", [&v] {
return reduce(par, v.begin(), v.end(), 0.0);
});
timeit("reduce, par_unseq", [&v] {
return reduce(par_unseq, v.begin(), v.end(), 0.0);
});
timeit("find, seq ", [&v] {
return find(seq, v.begin(), v.end(), 1.1) == v.end() ? 0.0 : 1.0;
});
timeit("find, par ", [&v] {
return find(par, v.begin(), v.end(), 1.1) == v.end() ? 0.0 : 1.0;
});
return 0;
}
Godbolt Listing lst-0819-godb.cpp, https://godbolt.org/z/qcT9o7YfG:
//#(compile) c++; compiler:g112; options:-O3 -std=c++23 -ltbb; libs:tbb@trunk
// https://godbolt.org/z/qcT9o7YfG
#include <algorithm> // find
#include <numeric> // reduce, accumulate
#include <execution> // std::execution
#include <iostream>
#include <chrono> // Zeitmessung
using namespace std::chrono;
long long millisSeit(steady_clock::time_point start) {
return duration_cast<milliseconds>(steady_clock::now()-start).count();
}
template <typename FUNC> void timeit(const char* title, FUNC func) {
auto start = steady_clock::now();
auto ret = func(); // ausführen
std::cout << title << ": " << millisSeit(start) << " ms" << std::endl;
}
int main() {
using namespace std::execution; // seq, par, par_unseq
using std::reduce; using std::accumulate; using std::find;
std::vector<double> v(600'000'000, 0.0); // 600 Millionen Elemente
for(auto&x:v) x = ::rand(); // mit Zufallswerten füllen
timeit("warmlaufen ", [&v] {
return reduce(seq, v.begin(), v.end(), 0.0);
});
timeit("accumulate ", [&v] {
return accumulate(v.begin(), v.end(), 0.0);
});
timeit("reduce, seq ", [&v] {
return reduce(seq, v.begin(), v.end(), 0.0);
});
timeit("reduce, par ", [&v] {
return reduce(par, v.begin(), v.end(), 0.0);
});
timeit("reduce, par_unseq", [&v] {
return reduce(par_unseq, v.begin(), v.end(), 0.0);
});
timeit("find, seq ", [&v] {
return find(seq, v.begin(), v.end(), 1.1) == v.end() ? 0.0 : 1.0;
});
timeit("find, par ", [&v] {
return find(par, v.begin(), v.end(), 1.1) == v.end() ? 0.0 : 1.0;
});
return 0;
}
Listing 25.5: View-Typen und ihre Adapter
Book listing lst-0820-book.cpp:
// https://godbolt.org/z/rrq1v5qPs
std::list lst{1, 2, 3, 4, 5, 6, 7, 8, 9};
auto take5 = rs::take_view{lst, 5}; // View via Typ
auto take6 = lst | vs::take(6); // View via Adapter
Godbolt Listing lst-0820-godb.cpp, https://godbolt.org/z/rrq1v5qPs:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/rrq1v5qPs
std::list lst{1, 2, 3, 4, 5, 6, 7, 8, 9};
auto take5 = rs::take_view{lst, 5}; // View via Typ
auto take6 = lst | vs::take(6); // View via Adapter
Listing 25.6: Besonders die C++23-Views lassen sich gut kombinieren.
Book listing lst-0821-book.cpp:
// https://godbolt.org/z/hYTv6f9eo
#include <ranges>
#include <array>
#include <string>
#include <iostream>
#include <string_view>
using namespace std::literals; using namespace std;
// Funktion für die Ausgabe von allem Möglichen
template <typename OBJ>
void print(OBJ&& obj, int level = 0) {
if constexpr(std::ranges::input_range<OBJ>) { // range
cout << '[';
for (const auto& elem : obj) print(elem, level+1);
cout << ']';
} else if constexpr(requires (OBJ tpl){ std::get<0>(tpl);}) { // tuple/pair
cout << "(";
print(get<0>(obj), level+1); print(get<1>(obj), level+1);
cout << ")";
} else cout << obj; // element
if (level == 0) cout << '\n';
}
int main() {
using namespace std::views; // ausnahmsweise für die Kürze
auto const nums = array{0, 0, 1, 1, 2, 2};
auto const animals = array{"cat"s, "dog"s};
print(iota(0, 5) | chunk(2)); // Ausgabe: [[01][23][4]]
print(nums | chunk_by(equal_to{})); // Ausgabe: [[00][11][22]]
print(iota(0, 5) | slide(3)); // Ausgabe: [[012][123][234]]
print(iota(0, 10) | stride(3)); // Ausgabe: [0369]
print(repeat(8) |take(5)); // Ausgabe: [88888]
print(zip_transform(plus{}, nums, nums)); // Ausgabe: [002244]
print(zip(iota(0, 3), iota(1, 4))); // Ausgabe: [(01)(12)(23)]
print(iota(0, 4) | adjacent<2>); // Ausgabe: [(01)(12)(23)]
print(iota(0, 4) | pairwise); // Ausgabe: [(01)(12)(23)]
print(iota(0, 4) | adjacent_transform<2>(plus{})); // Ausgabe: [135]
print(iota(0, 4) | pairwise_transform(plus{})); // Ausgabe: [135]
print(animals | join_with( '+' )); // Ausgabe: [cat+dog]
print(cartesian_product(iota(0, 2), "AZ"s)); // Ausgabe: [(0A)(0Z)(1A)(1Z)]
print(enumerate("APL"s)); // Ausgabe: [(0A)(1P)(2L)]
return 0;
}
Godbolt Listing lst-0821-godb.cpp, https://godbolt.org/z/hYTv6f9eo:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/hYTv6f9eo
#include <ranges>
#include <array>
#include <string>
#include <iostream>
#include <string_view>
using namespace std::literals; using namespace std;
// Funktion für die Ausgabe von allem Möglichen
template <typename OBJ>
void print(OBJ&& obj, int level = 0) {
if constexpr(std::ranges::input_range<OBJ>) { // range
cout << '[';
for (const auto& elem : obj) print(elem, level+1);
cout << ']';
} else if constexpr(requires (OBJ tpl){ std::get<0>(tpl);}) { // tuple/pair
cout << "(";
print(get<0>(obj), level+1); print(get<1>(obj), level+1);
cout << ")";
} else cout << obj; // element
if (level == 0) cout << '\n';
}
int main() {
using namespace std::views; // ausnahmsweise für die Kürze
auto const nums = array{0, 0, 1, 1, 2, 2};
auto const animals = array{"cat"s, "dog"s};
print(iota(0, 5) | chunk(2)); // Ausgabe: [[01][23][4]]
print(nums | chunk_by(equal_to{})); // Ausgabe: [[00][11][22]]
print(iota(0, 5) | slide(3)); // Ausgabe: [[012][123][234]]
print(iota(0, 10) | stride(3)); // Ausgabe: [0369]
print(repeat(8) |take(5)); // Ausgabe: [88888]
print(zip_transform(plus{}, nums, nums)); // Ausgabe: [002244]
print(zip(iota(0, 3), iota(1, 4))); // Ausgabe: [(01)(12)(23)]
print(iota(0, 4) | adjacent<2>); // Ausgabe: [(01)(12)(23)]
print(iota(0, 4) | pairwise); // Ausgabe: [(01)(12)(23)]
print(iota(0, 4) | adjacent_transform<2>(plus{})); // Ausgabe: [135]
print(iota(0, 4) | pairwise_transform(plus{})); // Ausgabe: [135]
print(animals | join_with( '+' )); // Ausgabe: [cat+dog]
print(cartesian_product(iota(0, 2), "AZ"s)); // Ausgabe: [(0A)(0Z)(1A)(1Z)]
print(enumerate("APL"s)); // Ausgabe: [(0A)(1P)(2L)]
return 0;
}
Listing 25.7: Funktionen müssen einen Range-Parameter als universelle Referenz bekommen.
Book listing lst-0824-book.cpp:
// https://godbolt.org/z/64zdMEe4r
void print(const auto& range) { // (ERR) kritisch: konstante Referenz
for (auto const& e : range) { cout << e; } cout << '\n';
}
vector vec{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
list lst{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
print(vec); // funktioniert auf direkten Containern
print(lst); // funktioniert auf direkten Containern
print(vec | vs::take(3)); // take mit vector klappt
print(lst | vs::take(3)); // take mit list klappt
print(vec | vs::drop(5)); // drop mit vector klappt
print(lst | vs::drop(5)); // (ERR) drop mit list klappt nicht!
Godbolt Listing lst-0824-godb.cpp, https://godbolt.org/z/64zdMEe4r:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/64zdMEe4r
void print(const auto& range) { // (ERR) kritisch: konstante Referenz
for (auto const& e : range) { cout << e; } cout << '\n';
}
vector vec{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
list lst{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
print(vec); // funktioniert auf direkten Containern
print(lst); // funktioniert auf direkten Containern
print(vec | vs::take(3)); // take mit vector klappt
print(lst | vs::take(3)); // take mit list klappt
print(vec | vs::drop(5)); // drop mit vector klappt
print(lst | vs::drop(5)); // (ERR) drop mit list klappt nicht!
Listing 25.8: Eine Funktion nur für Views und nicht für Container
Book listing lst-0825-book.cpp:
// https://godbolt.org/z/s1GjfWxv6
void print(ranges::view auto range) { // Wertparameter, eingeschränkt auf Views
for (auto const& e : range) { cout << e; } cout << '\n';
}
vector vec{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
list lst{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
print(vec); // (ERR) Verboten für Container, sehr gut!
print(vs::all(vec)); // Container in View umwandeln
print(vs::all(lst)); // Container in View umwandeln
print(vec | vs::take(3)); // take mit vector klappt
print(lst | vs::take(3)); // take mit list klappt
print(vec | vs::drop(5)); // drop mit vector klappt
print(lst | vs::drop(5)); // als Wertparameter klappt drop mit list
Godbolt Listing lst-0825-godb.cpp, https://godbolt.org/z/s1GjfWxv6:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/s1GjfWxv6
void print(ranges::view auto range) { // Wertparameter, eingeschränkt auf Views
for (auto const& e : range) { cout << e; } cout << '\n';
}
vector vec{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
list lst{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
print(vec); // (ERR) Verboten für Container, sehr gut!
print(vs::all(vec)); // Container in View umwandeln
print(vs::all(lst)); // Container in View umwandeln
print(vec | vs::take(3)); // take mit vector klappt
print(lst | vs::take(3)); // take mit list klappt
print(vec | vs::drop(5)); // drop mit vector klappt
print(lst | vs::drop(5)); // als Wertparameter klappt drop mit list
Listing 25.9: Suchen mit Prädikat
Book listing lst-0826-book.cpp:
// https://godbolt.org/z/3r5E1f9YP
#include <algorithm>
#include <iostream>
#include <vector>
#include <string>
#include <string_view>
#include <ranges>
using std::vector; using std::string; using std::string_view;
using namespace std::literals; using std::find_if;
vector<string> demo_split(string_view s) {
vector<string> result{};
auto it = s.begin();
while(it != s.end()) {
// bis normales Zeichen:
it = find_if(it, s.end(), [](char c) { return c!=' '; });
// bis Leerzeichen:
auto jt = find_if(it, s.end(), [](char c) { return c==' '; });
if(it!=s.end())
result.push_back(string(it, jt)); // Kopie ins Ergebnis
it = jt;
}
return result;
}
int main() {
auto text = "Der Text ist kurz"sv;
auto res = demo_split(text);
std::ranges::for_each(res, [](const string &e) {
std::cout << "[" << e << "] "; });
std::cout << '\n'; // Ausgabe: [Der] [Text] [ist] [kurz]
// oder gleich mit views::split:
for(auto word : text | std::views::split(" "sv)) {
std::cout << "[";
for(auto c : word) std::cout << c;
std::cout << "] ";
} // Ausgabe: [Der] [Text] [ist] [kurz]
}
Godbolt Listing lst-0826-godb.cpp, https://godbolt.org/z/3r5E1f9YP:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/3r5E1f9YP
#include <algorithm>
#include <iostream>
#include <vector>
#include <string>
#include <string_view>
#include <ranges>
using std::vector; using std::string; using std::string_view;
using namespace std::literals; using std::find_if;
vector<string> demo_split(string_view s) {
vector<string> result{};
auto it = s.begin();
while(it != s.end()) {
// bis normales Zeichen:
it = find_if(it, s.end(), [](char c) { return c!=' '; });
// bis Leerzeichen:
auto jt = find_if(it, s.end(), [](char c) { return c==' '; });
if(it!=s.end())
result.push_back(string(it, jt)); // Kopie ins Ergebnis
it = jt;
}
return result;
}
int main() {
auto text = "Der Text ist kurz"sv;
auto res = demo_split(text);
std::ranges::for_each(res, [](const string &e) {
std::cout << "[" << e << "] "; });
std::cout << '\n'; // Ausgabe: [Der] [Text] [ist] [kurz]
// oder gleich mit views::split:
for(auto word : text | std::views::split(" "sv)) {
std::cout << "[";
for(auto c : word) std::cout << c;
std::cout << "] ";
} // Ausgabe: [Der] [Text] [ist] [kurz]
}
Listing 25.10: Ein Palindrom mit einer Codezeile erkennen
Book listing lst-0827-book.cpp:
// https://godbolt.org/z/WqvM6KEEM
#include <algorithm>
#include <iostream>
#include <vector>
#include <string>
#include <string_view>
using std::string_view; using namespace std::literals; using std::cout;
auto istPalindrom(string_view sv) {
return std::ranges::equal(sv.begin(), sv.end(), sv.rbegin(), sv.rend()); };
int main() {
for(auto s : {"regallager"sv, "rentner"sv, "blutwurst"sv }) {
cout << s << " ist " << (istPalindrom(s)?"ein":"kein") << " Palindrom\n";
}
}
Godbolt Listing lst-0827-godb.cpp, https://godbolt.org/z/WqvM6KEEM:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/WqvM6KEEM
#include <algorithm>
#include <iostream>
#include <vector>
#include <string>
#include <string_view>
using std::string_view; using namespace std::literals; using std::cout;
auto istPalindrom(string_view sv) {
return std::ranges::equal(sv.begin(), sv.end(), sv.rbegin(), sv.rend()); };
int main() {
for(auto s : {"regallager"sv, "rentner"sv, "blutwurst"sv }) {
cout << s << " ist " << (istPalindrom(s)?"ein":"kein") << " Palindrom\n";
}
}
Listing 25.11: Auch »nur lesende« Algorithmen wie »for_each« können die Elemente verändern.
Book listing lst-0828-book.cpp:
// https://godbolt.org/z/jz1Gqo7d9
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> c{ 1,2,3,4 };
std::ranges::for_each(c, [](auto &n) { n*=n; }); // (ERR) modifizierend
std::cout << c[3] << '\n'; // Ausgabe: 16
}
Godbolt Listing lst-0828-godb.cpp, https://godbolt.org/z/jz1Gqo7d9:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/jz1Gqo7d9
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> c{ 1,2,3,4 };
std::ranges::for_each(c, [](auto &n) { n*=n; }); // (ERR) modifizierend
std::cout << c[3] << '\n'; // Ausgabe: 16
}
Listing 25.12: »transform« kann mit unterschiedlichen Typen jonglieren.
Book listing lst-0830-book.cpp:
// https://godbolt.org/z/7r4b8jdGr
#include <algorithm>
#include <iostream>
#include <vector>
#include <string>
using std::to_string; using std::string; using std::vector;
struct Squares {
mutable int n = 1;
int operator()() const { return n*n++; }
};
int main() {
vector<int> sq(10);
std::ranges::generate(sq, Squares{});
std::ranges::for_each(sq, [](auto n) {
std::cout << n << " "; });
std::cout << '\n'; // Ausgabe: 1 4 9 16 25 36 49 64 81 100
string a = "NCC-";
vector<int> b {1,7,0,1};
vector<string> c(4);
auto f = [](char c, int i) -> string { return c+to_string(i); };
std::ranges::transform(
a, // Eingabe 1
b, // Eingabe 2
c.begin(), // Ausgabe
f); // string f(char,int)
std::ranges::for_each(c, [](auto s) {
std::cout << s << " "; });
std::cout << '\n'; // Ausgabe: N1 C7 C0 -1
}
Godbolt Listing lst-0830-godb.cpp, https://godbolt.org/z/7r4b8jdGr:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/7r4b8jdGr
#include <algorithm>
#include <iostream>
#include <vector>
#include <string>
using std::to_string; using std::string; using std::vector;
struct Squares {
mutable int n = 1;
int operator()() const { return n*n++; }
};
int main() {
vector<int> sq(10);
std::ranges::generate(sq, Squares{});
std::ranges::for_each(sq, [](auto n) {
std::cout << n << " "; });
std::cout << '\n'; // Ausgabe: 1 4 9 16 25 36 49 64 81 100
string a = "NCC-";
vector<int> b {1,7,0,1};
vector<string> c(4);
auto f = [](char c, int i) -> string { return c+to_string(i); };
std::ranges::transform(
a, // Eingabe 1
b, // Eingabe 2
c.begin(), // Ausgabe
f); // string f(char,int)
std::ranges::for_each(c, [](auto s) {
std::cout << s << " "; });
std::cout << '\n'; // Ausgabe: N1 C7 C0 -1
}
Listing 25.13: Mit Range-Adaptern transformieren
Book listing lst-0831-book.cpp:
// https://godbolt.org/z/j9ozax8qE
#include <ranges> // zip_transform
// …
auto res = std::views::zip_transform(f, a, b); // Range-Adapter
for(auto s: res) { std::cout << s << " "; };
std::cout << '\n'; // Ausgabe: N1 C7 C0 -1
Godbolt Listing lst-0831-godb.cpp, https://godbolt.org/z/j9ozax8qE:
//#(compile) c++; compiler:g132; options:"-std=c++23"; libs:-
// https://godbolt.org/z/j9ozax8qE
#include <ranges> // zip_transform
// …
auto res = std::views::zip_transform(f, a, b); // Range-Adapter
for(auto s: res) { std::cout << s << " "; };
std::cout << '\n'; // Ausgabe: N1 C7 C0 -1
GodboltId:s53qx664K
Book listing lst-0832-book.cpp:
// https://godbolt.org/z/s53qx664K
#include <iostream>
#include <random> // default_random_engine
#include <string>
#include <iterator> // back_inserter
#include <algorithm> // sample
int main() {
std::default_random_engine zufall{};
const std::string in = "abcdefgh";
for(auto idx : {0,1,2,3}) {
std::string out;
std::ranges::sample(in, std::back_inserter(out), 5, zufall);
std::cout << out << '\n';
}
}
Godbolt Listing lst-0832-godb.cpp, https://godbolt.org/z/s53qx664K:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/s53qx664K
#include <iostream>
#include <random> // default_random_engine
#include <string>
#include <iterator> // back_inserter
#include <algorithm> // sample
int main() {
std::default_random_engine zufall{};
const std::string in = "abcdefgh";
for(auto idx : {0,1,2,3}) {
std::string out;
std::ranges::sample(in, std::back_inserter(out), 5, zufall);
std::cout << out << '\n';
}
}
Listing 25.14: Wirkungsweise der Mischmengenalgorithmen
Book listing lst-0833-book.cpp:
// https://godbolt.org/z/qW4hvE9s3
#include <algorithm>
#include <iostream>
#include <list>
#include <string>
#include <iterator> // ostream_iterator
#include <cctype> // toupper
using std::toupper;
int main() {
std::list a{ 1,2,4,4,4,7,7,9 };
std::list b{ 2,2,3,4,4,8 };
using Os = std::ostream_iterator<int>; // Typ des Ausgabeiterators
Os os{std::cout, " "}; // Streamausgabeiterator für int
auto run = [&a,&b,&os](auto algo) { // nutze a, b und os
algo(a.begin(), a.end(), b.begin(), b.end(), os); // Algorithmus aufrufen
std::cout << '\n';
};
// Ergebnisse der Algorithmen
using It = decltype(a.begin()); // Typ der Eingabeiteratoren
run(std::merge<It,It,Os>); // Ausgabe: 1 2 2 2 3 4 4 4 4 4 7 7 8 9
run(std::set_union<It,It,Os>); // Ausgabe: 1 2 2 3 4 4 4 7 7 8 9
run(std::set_intersection<It,It,Os>); // Ausgabe: 2 4 4
run(std::set_difference<It,It,Os>); // Ausgabe: 1 4 7 7 9
run(std::set_symmetric_difference<It,It,Os>); // Ausgabe: 1 2 3 4 7 7 8 9
// Mit Buchstaben wird es noch klarer
std::string x = "abdddggi";
std::string y = "BBCDDH";
using Us = std::ostream_iterator<char>; // Typ des Ausgabeiterators
Us us{std::cout, ""}; // Streamausgabeiterator für char
auto compare = [](auto c, auto d) { return toupper(c) < toupper(d); };
auto run2 = [&x,&y,&us,&compare](auto algo) { // nutze x, y und us
algo(x.begin(), x.end(), y.begin(), y.end(), us, compare);
std::cout << '\n';
};
// Ergebnisse der Algorithmen
using Jt = decltype(x.begin()); // Typ der Eingabeiteratoren
using Cm = decltype(compare); // Typ der Vergleichsfunktion
run2(std::merge<Jt,Jt,Us,Cm>); // Ausgabe: abBBCdddDDggHi
run2(std::set_union<Jt,Jt,Us,Cm>); // Ausgabe: abBCdddggHi
run2(std::set_intersection<Jt,Jt,Us,Cm>); // Ausgabe: bdd
run2(std::set_difference<Jt,Jt,Us,Cm>); // Ausgabe: adggi
run2(std::set_symmetric_difference<Jt,Jt,Us,Cm>); // Ausgabe: aBCdggHi
}
Godbolt Listing lst-0833-godb.cpp, https://godbolt.org/z/qW4hvE9s3:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/qW4hvE9s3
#include <algorithm>
#include <iostream>
#include <list>
#include <string>
#include <iterator> // ostream_iterator
#include <cctype> // toupper
using std::toupper;
int main() {
std::list a{ 1,2,4,4,4,7,7,9 };
std::list b{ 2,2,3,4,4,8 };
using Os = std::ostream_iterator<int>; // Typ des Ausgabeiterators
Os os{std::cout, " "}; // Streamausgabeiterator für int
auto run = [&a,&b,&os](auto algo) { // nutze a, b und os
algo(a.begin(), a.end(), b.begin(), b.end(), os); // Algorithmus aufrufen
std::cout << '\n';
};
// Ergebnisse der Algorithmen
using It = decltype(a.begin()); // Typ der Eingabeiteratoren
run(std::merge<It,It,Os>); // Ausgabe: 1 2 2 2 3 4 4 4 4 4 7 7 8 9
run(std::set_union<It,It,Os>); // Ausgabe: 1 2 2 3 4 4 4 7 7 8 9
run(std::set_intersection<It,It,Os>); // Ausgabe: 2 4 4
run(std::set_difference<It,It,Os>); // Ausgabe: 1 4 7 7 9
run(std::set_symmetric_difference<It,It,Os>); // Ausgabe: 1 2 3 4 7 7 8 9
// Mit Buchstaben wird es noch klarer
std::string x = "abdddggi";
std::string y = "BBCDDH";
using Us = std::ostream_iterator<char>; // Typ des Ausgabeiterators
Us us{std::cout, ""}; // Streamausgabeiterator für char
auto compare = [](auto c, auto d) { return toupper(c) < toupper(d); };
auto run2 = [&x,&y,&us,&compare](auto algo) { // nutze x, y und us
algo(x.begin(), x.end(), y.begin(), y.end(), us, compare);
std::cout << '\n';
};
// Ergebnisse der Algorithmen
using Jt = decltype(x.begin()); // Typ der Eingabeiteratoren
using Cm = decltype(compare); // Typ der Vergleichsfunktion
run2(std::merge<Jt,Jt,Us,Cm>); // Ausgabe: abBBCdddDDggHi
run2(std::set_union<Jt,Jt,Us,Cm>); // Ausgabe: abBCdddggHi
run2(std::set_intersection<Jt,Jt,Us,Cm>); // Ausgabe: bdd
run2(std::set_difference<Jt,Jt,Us,Cm>); // Ausgabe: adggi
run2(std::set_symmetric_difference<Jt,Jt,Us,Cm>); // Ausgabe: aBCdggHi
}
GodboltId:73hTTM7s6
Book listing lst-0834-book.cpp:
// https://godbolt.org/z/73hTTM7s6
#include <iostream>
#include <algorithm>
#include <string>
void one(std::string &seq) {
std::ranges::next_permutation(seq);
std::cout << seq << '\n';
}
int main() {
std::string seq = "BDK";
std::cout << seq << '\n'; // Ausgabe: BDK
auto limit = 3*2*1; // n!
for(int i=0; i<limit; ++i)
one(seq);
// Hier ist die Sequenz wieder in ihrem Ursprungszustand.
}
Godbolt Listing lst-0834-godb.cpp, https://godbolt.org/z/73hTTM7s6:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/73hTTM7s6
#include <iostream>
#include <algorithm>
#include <string>
void one(std::string &seq) {
std::ranges::next_permutation(seq);
std::cout << seq << '\n';
}
int main() {
std::string seq = "BDK";
std::cout << seq << '\n'; // Ausgabe: BDK
auto limit = 3*2*1; // n!
for(int i=0; i<limit; ++i)
one(seq);
// Hier ist die Sequenz wieder in ihrem Ursprungszustand.
}
Listing 25.15: »accumulate«
Book listing lst-0835-book.cpp:
// https://godbolt.org/z/8sEdxd5jP
#include <numeric> // accumulate
#include <functional> // multiplies
#include <algorithm> // transform, fold_left
#include <iostream>
#include <vector>
using std::accumulate; using std::cout; using std::vector; using std::multiplies;
namespace rs = std::ranges;
int main() {
vector data{ 2, 3, 5, 10, 20 };
cout << accumulate(data.begin(),data.end(),0)<<'\n'; // +, Ausgabe: 40
cout << rs::fold_left(data, 1, multiplies<int>{})<<'\n'; // *, 6000
vector<bool> gerade( data.size() );
std::transform( data.begin(), data.end(), gerade.begin(),
[](auto n) { return n%2==0; });
for(auto b : gerade) {
cout << ( b ? "gerade " : "ungerade ");
}
cout << "\n"; // Ausgabe: gerade ungerade ungerade gerade gerade
auto sindAlleGerade = accumulate(gerade.begin(), gerade.end(), true,
[](auto b, auto c) { return b&&c; });
if(sindAlleGerade) {
cout << "alles gerade Zahlen\n";
} else {
cout << "ungerade Zahlen dabei\n"; // das ist die Ausgabe
}
}
Godbolt Listing lst-0835-godb.cpp, https://godbolt.org/z/8sEdxd5jP:
//#(compile) c++; compiler:g132; options:"-std=c++23"; libs:-
// https://godbolt.org/z/8sEdxd5jP
#include <numeric> // accumulate
#include <functional> // multiplies
#include <algorithm> // transform, fold_left
#include <iostream>
#include <vector>
using std::accumulate; using std::cout; using std::vector; using std::multiplies;
namespace rs = std::ranges;
int main() {
vector data{ 2, 3, 5, 10, 20 };
cout << accumulate(data.begin(),data.end(),0)<<'\n'; // +, Ausgabe: 40
cout << rs::fold_left(data, 1, multiplies<int>{})<<'\n'; // *, 6000
vector<bool> gerade( data.size() );
std::transform( data.begin(), data.end(), gerade.begin(),
[](auto n) { return n%2==0; });
for(auto b : gerade) {
cout << ( b ? "gerade " : "ungerade ");
}
cout << "\n"; // Ausgabe: gerade ungerade ungerade gerade gerade
auto sindAlleGerade = accumulate(gerade.begin(), gerade.end(), true,
[](auto b, auto c) { return b&&c; });
if(sindAlleGerade) {
cout << "alles gerade Zahlen\n";
} else {
cout << "ungerade Zahlen dabei\n"; // das ist die Ausgabe
}
}
Listing 25.16: »adjacent_difference« und »pairwise_transform«
Book listing lst-0836-book.cpp:
// https://godbolt.org/z/z4ajz5E5P
#include <numeric> // adjacent_difference
#include <functional> // plus
#include <algorithm> // copy
#include <iostream>
#include <iterator> // ostream_iterator
#include <vector>
#include <ranges> // pairwise_transform
using std::cout; using std::vector; namespace vs = std::views;
int main() {
// Streamausgabeiterator für int;
std::ostream_iterator<int> os{std::cout, " "};
vector data{ 1, -1, 2, -2, -4, 4, -6, 6 };
std::copy(data.begin(), data.end (), os);
cout << '\n'; // Ausgabe: 1 –1 2 –2 –4 4 –6 6
vector<int> res( data.size()-1 ); // Platz für Ergebnis
// Ergebnisse nach res schreiben:
adjacent_difference(data.begin(), data.end(), res.begin());
std::copy (res.begin(), res.end (), os);
cout << '\n'; // Ausgabe: 1 –2 3 –4 –2 8 –10
// gleich nach os schreiben:
adjacent_difference(data.begin(), data.end(), os, std::plus<int>{});
cout << '\n'; // Ausgabe: 1 0 1 0 –6 0 –2 0
// oder via Range-Adapter:
for(auto e: vs::pairwise_transform(data, std::plus<int>{}))
cout << e << ' ';
cout << '\n'; // Ausgabe: 0 1 0 –6 0 –2 0
}
Godbolt Listing lst-0836-godb.cpp, https://godbolt.org/z/z4ajz5E5P:
//#(compile) c++; compiler:g132; options:"-std=c++23"; libs:-
// https://godbolt.org/z/z4ajz5E5P
#include <numeric> // adjacent_difference
#include <functional> // plus
#include <algorithm> // copy
#include <iostream>
#include <iterator> // ostream_iterator
#include <vector>
#include <ranges> // pairwise_transform
using std::cout; using std::vector; namespace vs = std::views;
int main() {
// Streamausgabeiterator für int;
std::ostream_iterator<int> os{std::cout, " "};
vector data{ 1, -1, 2, -2, -4, 4, -6, 6 };
std::copy(data.begin(), data.end (), os);
cout << '\n'; // Ausgabe: 1 –1 2 –2 –4 4 –6 6
vector<int> res( data.size()-1 ); // Platz für Ergebnis
// Ergebnisse nach res schreiben:
adjacent_difference(data.begin(), data.end(), res.begin());
std::copy (res.begin(), res.end (), os);
cout << '\n'; // Ausgabe: 1 –2 3 –4 –2 8 –10
// gleich nach os schreiben:
adjacent_difference(data.begin(), data.end(), os, std::plus<int>{});
cout << '\n'; // Ausgabe: 1 0 1 0 –6 0 –2 0
// oder via Range-Adapter:
for(auto e: vs::pairwise_transform(data, std::plus<int>{}))
cout << e << ' ';
cout << '\n'; // Ausgabe: 0 1 0 –6 0 –2 0
}
Listing 25.17: »iota«, »stride« und »take«
Book listing lst-0837-book.cpp:
// https://godbolt.org/z/aPoe3d873
#include <numeric> // accumulate, iota
#include <algorithm> // copy
#include <iostream>
#include <iterator> // ostream_iterator
#include <vector>
#include <ranges> // iota, take, stride
using std::accumulate; using std::cout; using std::vector;
namespace vs = std::views;
struct Generator {
int state_;
void operator++() { state_ += state_; }
operator int() { return state_; }
};
int main() {
std::ostream_iterator<int> os{std::cout, " "}; // Streamausgabeiterator für int
vector<int> data(7);
std::iota(data.begin(), data.end(), 10);
std::copy(data.begin(), data.end (), os);
cout << '\n'; // Ausgabe: 10 11 12 13 14 15 16
vector<int> seq(7);
std::iota(seq.begin(), seq.end(), Generator{2});
std::copy(seq.begin(), seq.end(), os);
cout << '\n'; // Ausgabe: 2 4 8 16 32 64 128
for(auto i: vs::iota(0) | vs::stride(3) | vs::take(6))
cout << i << ' ';
cout << '\n'; // Ausgabe: 0 3 6 9 12 15
}
Godbolt Listing lst-0837-godb.cpp, https://godbolt.org/z/aPoe3d873:
//#(compile) c++; compiler:g132; options:"-std=c++23"; libs:-
// https://godbolt.org/z/aPoe3d873
#include <numeric> // accumulate, iota
#include <algorithm> // copy
#include <iostream>
#include <iterator> // ostream_iterator
#include <vector>
#include <ranges> // iota, take, stride
using std::accumulate; using std::cout; using std::vector;
namespace vs = std::views;
struct Generator {
int state_;
void operator++() { state_ += state_; }
operator int() { return state_; }
};
int main() {
std::ostream_iterator<int> os{std::cout, " "}; // Streamausgabeiterator für int
vector<int> data(7);
std::iota(data.begin(), data.end(), 10);
std::copy(data.begin(), data.end (), os);
cout << '\n'; // Ausgabe: 10 11 12 13 14 15 16
vector<int> seq(7);
std::iota(seq.begin(), seq.end(), Generator{2});
std::copy(seq.begin(), seq.end(), os);
cout << '\n'; // Ausgabe: 2 4 8 16 32 64 128
for(auto i: vs::iota(0) | vs::stride(3) | vs::take(6))
cout << i << ' ';
cout << '\n'; // Ausgabe: 0 3 6 9 12 15
}
Listing 25.18: »inclusive_scan« und »exclusive_scan«
Book listing lst-0838-book.cpp:
// https://godbolt.org/z/qcWsdedMz
#include <numeric> // *_scan
#include <iostream>
#include <vector>
using std::inclusive_scan; using std::exclusive_scan;
std::ostream& operator<<=(std::ostream&os, const std::vector<int>&data) {
for(auto &e : data) os << e << ' '; return os << '\n';
}
int main() {
std::vector data{ 1, 3, 10, 18, 30, 50 };
std::vector<int> result(6); // 6 Elemente
auto plus = [](auto a, auto b) { return a+b; };
inclusive_scan(data.begin(),data.end(), result.begin(), plus, 100);
std::cout <<= result;
// Ausgabe: 101 104 114 132 162 212
exclusive_scan(data.begin(),data.end(), result.begin(), 100);
std::cout <<= result;
// Ausgabe: 100 101 104 114 132 162
}
Godbolt Listing lst-0838-godb.cpp, https://godbolt.org/z/qcWsdedMz:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/qcWsdedMz
#include <numeric> // *_scan
#include <iostream>
#include <vector>
using std::inclusive_scan; using std::exclusive_scan;
std::ostream& operator<<=(std::ostream&os, const std::vector<int>&data) {
for(auto &e : data) os << e << ' '; return os << '\n';
}
int main() {
std::vector data{ 1, 3, 10, 18, 30, 50 };
std::vector<int> result(6); // 6 Elemente
auto plus = [](auto a, auto b) { return a+b; };
inclusive_scan(data.begin(),data.end(), result.begin(), plus, 100);
std::cout <<= result;
// Ausgabe: 101 104 114 132 162 212
exclusive_scan(data.begin(),data.end(), result.begin(), 100);
std::cout <<= result;
// Ausgabe: 100 101 104 114 132 162
}
GodboltId:dKPbjj1f8
Book listing lst-0839-book.cpp:
// https://godbolt.org/z/dKPbjj1f8
#include <iostream>
#include <memory> // uninitialized_copy
#include <alloca.h> // alloca (Linux)
#include <list>
int main () {
const std::list input{1,9,2,6,6,6,8};
const auto SZ = input.size();
// uninitialisierter Speicherbereich:
int* ziel = (int*)alloca(sizeof(int) * SZ); // Platz für 7 ints
std::uninitialized_copy(input.begin(), input.end(), ziel);
// Testausgabe
for(int idx=0; idx<SZ; ++idx) {
std::cout << ziel[idx] << ' ';
}
std::cout << '\n'; // Ausgabe: 1 9 2 6 6 6 8
}
Godbolt Listing lst-0839-godb.cpp, https://godbolt.org/z/dKPbjj1f8:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/dKPbjj1f8
#include <iostream>
#include <memory> // uninitialized_copy
#include <alloca.h> // alloca (Linux)
#include <list>
int main () {
const std::list input{1,9,2,6,6,6,8};
const auto SZ = input.size();
// uninitialisierter Speicherbereich:
int* ziel = (int*)alloca(sizeof(int) * SZ); // Platz für 7 ints
std::uninitialized_copy(input.begin(), input.end(), ziel);
// Testausgabe
for(int idx=0; idx<SZ; ++idx) {
std::cout << ziel[idx] << ' ';
}
std::cout << '\n'; // Ausgabe: 1 9 2 6 6 6 8
}
Listing 25.19: Ein eigener Algorithmus
Book listing lst-0841-book.cpp:
// https://godbolt.org/z/n8ErWj7j6
template<typename It, typename Func>
void adjacent_pair(It begin, It end, Func func) {
if(begin != end) {
It prev = begin; // erstes Argument
++begin; // zweites Argument
for(; begin != end; ++begin, ++prev) {
func(*prev, *begin);
}
}
}
Godbolt Listing lst-0841-godb.cpp, https://godbolt.org/z/n8ErWj7j6:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/n8ErWj7j6
template<typename It, typename Func>
void adjacent_pair(It begin, It end, Func func) {
if(begin != end) {
It prev = begin; // erstes Argument
++begin; // zweites Argument
for(; begin != end; ++begin, ++prev) {
func(*prev, *begin);
}
}
}
Listing 25.20: Der Einsatz von adjacent_pair
Book listing lst-0842-book.cpp:
// https://godbolt.org/z/91jj8Toqs
#include <vector>
#include <iostream>
// … adjacent_pair von oben hier …
int main() {
std::vector v{1,2,3,4};
auto f = [](auto a, auto b) { std::cout << (a+b) << ' '; };
adjacent_pair(v.begin(), v.end(), f); // 3 5 7
std::cout << '\n';
std::vector x{4,8};
adjacent_pair(x.begin(), x.end(), f); // 12
std::cout << '\n';
std::vector w{4};
adjacent_pair(w.begin(), w.end(), f); // nichts
std::cout << '\n';
std::vector<int> y{};
adjacent_pair(y.begin(), y.end(), f); // nichts
std::cout << '\n';
}
Godbolt Listing lst-0842-godb.cpp, https://godbolt.org/z/91jj8Toqs:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/91jj8Toqs
#include <vector>
#include <iostream>
// … adjacent_pair von oben hier …
int main() {
std::vector v{1,2,3,4};
auto f = [](auto a, auto b) { std::cout << (a+b) << ' '; };
adjacent_pair(v.begin(), v.end(), f); // 3 5 7
std::cout << '\n';
std::vector x{4,8};
adjacent_pair(x.begin(), x.end(), f); // 12
std::cout << '\n';
std::vector w{4};
adjacent_pair(w.begin(), w.end(), f); // nichts
std::cout << '\n';
std::vector<int> y{};
adjacent_pair(y.begin(), y.end(), f); // nichts
std::cout << '\n';
}
Listing 25.21: Eigene Range-Adapter für Views
Book listing lst-0843-book.cpp:
// https://godbolt.org/z/dfoorEdYT
#include <ranges>
#include <iostream>
#include <string_view>
#include <vector>
using namespace std::literals;
using namespace std; namespace vs = std::views; namespace rs = std::ranges;
// Beispiel 1
class Add_1: public rs::range_adaptor_closure<Add_1> {
// von Hilfsklasse ableiten
public:
template<rs::input_range R>
constexpr auto operator()(R&& r) const { // universelle Referenz
return forward<R>(r) // universelle Referenz erhalten
| vs::transform([](auto i) {return i+1;}); // Ihre Implementierung
}
};
Add_1 add_1{}; // Range-Adapter erzeugen
// Beispiel 2
class Dna_to_rna: public rs::range_adaptor_closure<Dna_to_rna> { // ableiten
public:
template<rs::input_range R>
constexpr auto operator()(R&& r) const { // universelle Referenz
return forward<R>(r) // universelle Referenz erhalten
| vs::transform([](char c) // Ihre Implementierung
{
switch(c) {
case 'T': return 'U';
case 't': return 'u';
default: return c;
}
});
}
};
Dna_to_rna dna_to_rna{}; // Range-Adapter erzeugen
// Beispiele benutzen
int main() {
vector vec{1, 2, 3, 4, 5};
for(auto i: vec | add_1) // benutzen
cout << i << ' ';
cout << '\n'; // Ausgabe: 2 3 4 5 6
auto telo_rep = "TTAGGGTTAGGGTTAGGGTTAGGGT"sv;
for(auto c: telo_rep | dna_to_rna) // benutzen
cout << c;
cout << '\n'; // Ausgabe: UUAGGGUUAGGGUUAGGGUUAGGGU
}
Godbolt Listing lst-0843-godb.cpp, https://godbolt.org/z/dfoorEdYT:
//#(compile) c++; compiler:g132; options:"-std=c++23"; libs:-
// https://godbolt.org/z/dfoorEdYT
#include <ranges>
#include <iostream>
#include <string_view>
#include <vector>
using namespace std::literals;
using namespace std; namespace vs = std::views; namespace rs = std::ranges;
// Beispiel 1
class Add_1: public rs::range_adaptor_closure<Add_1> {
// von Hilfsklasse ableiten
public:
template<rs::input_range R>
constexpr auto operator()(R&& r) const { // universelle Referenz
return forward<R>(r) // universelle Referenz erhalten
| vs::transform([](auto i) {return i+1;}); // Ihre Implementierung
}
};
Add_1 add_1{}; // Range-Adapter erzeugen
// Beispiel 2
class Dna_to_rna: public rs::range_adaptor_closure<Dna_to_rna> { // ableiten
public:
template<rs::input_range R>
constexpr auto operator()(R&& r) const { // universelle Referenz
return forward<R>(r) // universelle Referenz erhalten
| vs::transform([](char c) // Ihre Implementierung
{
switch(c) {
case 'T': return 'U';
case 't': return 'u';
default: return c;
}
});
}
};
Dna_to_rna dna_to_rna{}; // Range-Adapter erzeugen
// Beispiele benutzen
int main() {
vector vec{1, 2, 3, 4, 5};
for(auto i: vec | add_1) // benutzen
cout << i << ' ';
cout << '\n'; // Ausgabe: 2 3 4 5 6
auto telo_rep = "TTAGGGTTAGGGTTAGGGTTAGGGT"sv;
for(auto c: telo_rep | dna_to_rna) // benutzen
cout << c;
cout << '\n'; // Ausgabe: UUAGGGUUAGGGUUAGGGUUAGGGU
}
Listing 26.1: Mit einem »vector« können Sie ein »set« simulieren.
Book listing lst-0844-book.cpp:
// https://godbolt.org/z/8d8qPWPcG
#include <vector>
#include <iostream>
#include <algorithm>
using std::vector; using std::ostream; using std::cout;
int main() {
vector<int> data{};
data.reserve(400); // Platz für 400 Elemente
// Phase 1: befüllen
for(int idx = 1; idx <= 20; ++idx) {
for(int val = 0; val < 20; ++val) {
data.push_back(val % idx); // irgendwas zwischen 0 und 19
}
}
cout << data.size() << '\n'; // 400 Elemente zwischen 0 und 19
// Nachbereitung Phase 1: set-Äquivalent erstellen
std::sort(data.begin(), data.end()); // Vorbereitung für unique
auto wo = std::unique(data.begin(), data.end()); // doppelte ans Ende
data.erase(wo, data.end()); // doppelte wegräumen
data.shrink_to_fit();
cout << data.size() << '\n'; // nur noch 20 Elemente
// Phase 2: benutzen
for(auto &e:data)
cout << e << ' '; // Ausgabe: 0 1 2 .. 18 19
cout << '\n';
auto it = std::lower_bound(data.begin(), data.end(), 16); // suche Wert
if(it!=data.end() && *it == 16)
cout << "gefunden!\n";
if(std::binary_search(data.begin(), data.end(), 7)) // ja oder nein
cout << "auch gefunden!\n";
}
Godbolt Listing lst-0844-godb.cpp, https://godbolt.org/z/8d8qPWPcG:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/8d8qPWPcG
#include <vector>
#include <iostream>
#include <algorithm>
using std::vector; using std::ostream; using std::cout;
int main() {
vector<int> data{};
data.reserve(400); // Platz für 400 Elemente
// Phase 1: befüllen
for(int idx = 1; idx <= 20; ++idx) {
for(int val = 0; val < 20; ++val) {
data.push_back(val % idx); // irgendwas zwischen 0 und 19
}
}
cout << data.size() << '\n'; // 400 Elemente zwischen 0 und 19
// Nachbereitung Phase 1: set-Äquivalent erstellen
std::sort(data.begin(), data.end()); // Vorbereitung für unique
auto wo = std::unique(data.begin(), data.end()); // doppelte ans Ende
data.erase(wo, data.end()); // doppelte wegräumen
data.shrink_to_fit();
cout << data.size() << '\n'; // nur noch 20 Elemente
// Phase 2: benutzen
for(auto &e:data)
cout << e << ' '; // Ausgabe: 0 1 2 .. 18 19
cout << '\n';
auto it = std::lower_bound(data.begin(), data.end(), 16); // suche Wert
if(it!=data.end() && *it == 16)
cout << "gefunden!\n";
if(std::binary_search(data.begin(), data.end(), 7)) // ja oder nein
cout << "auch gefunden!\n";
}
GodboltId:fv3963reh
Book listing lst-0845-book.cpp:
// https://godbolt.org/z/fv3963reh
#include <iostream> // cout
#include <algorithm> // copy
#include <iterator> // ostream_iterator
#include <vector>
int main() {
std::vector<char> pfad{};
for (char ch = 'a'; ch <= 'z'; ++ch) {
pfad.push_back(ch);
}
std::ranges::copy(pfad, // hier alles, geht aber auch mit anderen Ranges
std::ostream_iterator<char>(std::cout, " ") // kopiere nach cout, Separator " "
);
}
Godbolt Listing lst-0845-godb.cpp, https://godbolt.org/z/fv3963reh:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/fv3963reh
#include <iostream> // cout
#include <algorithm> // copy
#include <iterator> // ostream_iterator
#include <vector>
int main() {
std::vector<char> pfad{};
for (char ch = 'a'; ch <= 'z'; ++ch) {
pfad.push_back(ch);
}
std::ranges::copy(pfad, // hier alles, geht aber auch mit anderen Ranges
std::ostream_iterator<char>(std::cout, " ") // kopiere nach cout, Separator " "
);
}
Listing 26.2: Sie erhalten ein um ein Element vergrößertes Array zurück.
Book listing lst-0846-book.cpp:
// https://godbolt.org/z/jT7raEfKa
#include <iostream>
#include <array>
#include <vector>
#include <string>
using std::array; using std::move; using std::forward;
// == array vergrößern ==
template<typename T, size_t S, std::size_t... Idx>
constexpr array<T, S+1>
help_append(array<T, S>&& data, T&& elem, std::index_sequence<Idx...>) {
return { std::get<Idx>(forward<array<T, S>>(data))..., forward<T>(elem) };
}
template<typename T, size_t S>
constexpr auto
append(array<T, S> data, T elem) {
return help_append(move(data), move(elem),
std::make_index_sequence<S>{});
}
// == Beispiel ==
class Picture { // Nullerregel; verschiebbar
std::vector<char> data_; // viele Daten
std::string name_;
public:
explicit Picture(const std::string& name) : data_(1000,0), name_{name}
{ /* ... hier Bild laden ... */ }
auto name() const { return name_; }
};
int main() {
// vorher
array pics{Picture{"Mona"}, Picture{"Schrei"}, Picture{"Vincent"}};
std::cout << pics[0].name() << '\n'; // Ausgabe: Mona
// vergrößern
Picture neu { "Uhren" };
auto mehr = append(move(pics), move(neu));
// nachher
std::cout << pics[0].name() << '\n'; // Ausgabe:
std::cout << mehr[0].name() << '\n'; // Ausgabe: Mona
std::cout << mehr[3].name() << '\n'; // Ausgabe: Uhren
}
Godbolt Listing lst-0846-godb.cpp, https://godbolt.org/z/jT7raEfKa:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/jT7raEfKa
#include <iostream>
#include <array>
#include <vector>
#include <string>
using std::array; using std::move; using std::forward;
// == array vergrößern ==
template<typename T, size_t S, std::size_t... Idx>
constexpr array<T, S+1>
help_append(array<T, S>&& data, T&& elem, std::index_sequence<Idx...>) {
return { std::get<Idx>(forward<array<T, S>>(data))..., forward<T>(elem) };
}
template<typename T, size_t S>
constexpr auto
append(array<T, S> data, T elem) {
return help_append(move(data), move(elem),
std::make_index_sequence<S>{});
}
// == Beispiel ==
class Picture { // Nullerregel; verschiebbar
std::vector<char> data_; // viele Daten
std::string name_;
public:
explicit Picture(const std::string& name) : data_(1000,0), name_{name}
{ /* ... hier Bild laden ... */ }
auto name() const { return name_; }
};
int main() {
// vorher
array pics{Picture{"Mona"}, Picture{"Schrei"}, Picture{"Vincent"}};
std::cout << pics[0].name() << '\n'; // Ausgabe: Mona
// vergrößern
Picture neu { "Uhren" };
auto mehr = append(move(pics), move(neu));
// nachher
std::cout << pics[0].name() << '\n'; // Ausgabe:
std::cout << mehr[0].name() << '\n'; // Ausgabe: Mona
std::cout << mehr[3].name() << '\n'; // Ausgabe: Uhren
}
Listing 26.3: »append« zur Laufzeit
Book listing lst-0850-book.cpp:
// https://godbolt.org/z/MMP16Mj3W
#include <iostream>
#include <array>
#include <string>
using std::array;
template<typename T, size_t S>
auto append(const array<T, S>& data, T elem) {
array<T, S+1> result {};
for(auto i=0u; i < data.size(); ++i)
result[i] = data[i];
result[S] =elem;
return result;
}
int main() {
// vorher
array pics { 3, 4, 5 };
std::cout << pics[0] << '\n'; // Ausgabe: 3
// vergrößern
auto mehr = append(pics, 77);
// nachher
std::cout << mehr[3] << '\n'; // Ausgabe: 77
}
Godbolt Listing lst-0850-godb.cpp, https://godbolt.org/z/MMP16Mj3W:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/MMP16Mj3W
#include <iostream>
#include <array>
#include <string>
using std::array;
template<typename T, size_t S>
auto append(const array<T, S>& data, T elem) {
array<T, S+1> result {};
for(auto i=0u; i < data.size(); ++i)
result[i] = data[i];
result[S] =elem;
return result;
}
int main() {
// vorher
array pics { 3, 4, 5 };
std::cout << pics[0] << '\n'; // Ausgabe: 3
// vergrößern
auto mehr = append(pics, 77);
// nachher
std::cout << mehr[3] << '\n'; // Ausgabe: 77
}
Listing 26.4: Verschiedene Implementierungen eines Algorithmus, unterschieden anhand von Concepts
Book listing lst-0851-book.cpp:
// https://godbolt.org/z/scE81KfEa
#include <iostream>
#include <vector>
#include <list>
#include <ranges>
namespace rs = std::ranges;
template<rs::range R>
void alg(R&& range) {
if constexpr(rs::random_access_range<R>)
std::cout << "wahlfrei.\n";
else if constexpr(rs::bidirectional_range<R>)
std::cout << "bidirektional, aber nicht wahlfrei\n";
else static_assert(false, "nicht unterstützter Range-Typ");
}
int main() {
std::vector<int> vec {}; // vector ist wahlfrei
alg(vec);
std::list<int> lst; // list ist nur bidirektional
alg(lst);
std::istreambuf_iterator<char> i1{std::cin}, i2{}; // nicht einmal bidirektional
auto fwd = rs::subrange{i1, i2};
alg(fwd); // (ERR) Fehler: keine passende Implementierung
}
Godbolt Listing lst-0851-godb.cpp, https://godbolt.org/z/scE81KfEa:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/scE81KfEa
#include <iostream>
#include <vector>
#include <list>
#include <ranges>
namespace rs = std::ranges;
template<rs::range R>
void alg(R&& range) {
if constexpr(rs::random_access_range<R>)
std::cout << "wahlfrei.\n";
else if constexpr(rs::bidirectional_range<R>)
std::cout << "bidirektional, aber nicht wahlfrei\n";
else static_assert(false, "nicht unterstützter Range-Typ");
}
int main() {
std::vector<int> vec {}; // vector ist wahlfrei
alg(vec);
std::list<int> lst; // list ist nur bidirektional
alg(lst);
std::istreambuf_iterator<char> i1{std::cin}, i2{}; // nicht einmal bidirektional
auto fwd = rs::subrange{i1, i2};
alg(fwd); // (ERR) Fehler: keine passende Implementierung
}
Listing 27.1: Den Stream als Referenz zurückzugeben, ermöglicht das Aneinanderhängen.
Book listing lst-0854-book.cpp:
// https://godbolt.org/z/Th66Y9WvE
#include <iostream> // cin, cout
int main() {
int val1, val2;
std::cout << "Bitte 2 int-Werte: ";
std::cin >> val1 >> val2;
std::cout << val1 << " : " << val2 << std::endl;
}
Godbolt Listing lst-0854-godb.cpp, https://godbolt.org/z/Th66Y9WvE:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Th66Y9WvE
#include <iostream> // cin, cout
int main() {
int val1, val2;
std::cout << "Bitte 2 int-Werte: ";
std::cin >> val1 >> val2;
std::cout << val1 << " : " << val2 << std::endl;
}
Listing 27.2: Unformatierte Eingabe aus Streams
Book listing lst-0856-book.cpp:
// https://godbolt.org/z/rP6vMM1Gr
#include <iostream>
using std::cout; using std::cin; using std::endl;
int main() {
const unsigned int MAX = 10;
char buffer[MAX] = {0};
cout << "Eingabe getline : ";
cin.getline(buffer, MAX);
cout << std::cin.gcount()
<< " Zeichen wurden eingelesen\n";
for(auto c : buffer) {
if(c && c!='\0') cout.put(c);
}
cin.ignore(MAX, '\n');
cout << "\nEingabe machen (mit . beenden) : ";
char ch=0;
while(cin.get(ch)) {
if(ch == '.') break;
cout.put(ch);
}
cout << "Eingabe beendet" << endl;
}
Godbolt Listing lst-0856-godb.cpp, https://godbolt.org/z/rP6vMM1Gr:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/rP6vMM1Gr
#include <iostream>
using std::cout; using std::cin; using std::endl;
int main() {
const unsigned int MAX = 10;
char buffer[MAX] = {0};
cout << "Eingabe getline : ";
cin.getline(buffer, MAX);
cout << std::cin.gcount()
<< " Zeichen wurden eingelesen\n";
for(auto c : buffer) {
if(c && c!='\0') cout.put(c);
}
cin.ignore(MAX, '\n');
cout << "\nEingabe machen (mit . beenden) : ";
char ch=0;
while(cin.get(ch)) {
if(ch == '.') break;
cout.put(ch);
}
cout << "Eingabe beendet" << endl;
}
Listing 27.3: Zustandsprüfungen bei Streams
Book listing lst-0858-book.cpp:
// https://godbolt.org/z/rq3eGP3cv
#include <fstream>
#include <iostream>
using std::cout; using std::cin; using std::ofstream;
void checkIOstate(std::ios& stream) {
if( stream.good() ) {
cout << "Alles in Ordnung\n";
} else if( stream.bad() ) {
cout << "Fataler Fehler\n";
} else if( stream.fail()) {
cout << "Fehler bei der Ein-/Ausgabe\n";
if( stream.eof()) {
cout << "Ende des Datenstroms erreicht\n";
}
}
stream.clear();
}
int main() {
int val=0;
cout << "Wert eingeben: ";
cin >> val;
checkIOstate( cin );
std::ifstream file;
file.open("nichtvorhanden.text");
checkIOstate(file);
std::fstream fstr;
fstr.open("neueDatei.txt",
ofstream::out | ofstream::in
| ofstream::binary | ofstream::trunc);
fstr << "Text in der Datei\n";
fstr.seekp(std::ios_base::beg);
char ch;
while( fstr.good()) {
fstr.get(ch);
if(fstr.good()) cout.put(ch);
}
checkIOstate(fstr);
}
Godbolt Listing lst-0858-godb.cpp, https://godbolt.org/z/rq3eGP3cv:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/rq3eGP3cv
#include <fstream>
#include <iostream>
using std::cout; using std::cin; using std::ofstream;
void checkIOstate(std::ios& stream) {
if( stream.good() ) {
cout << "Alles in Ordnung\n";
} else if( stream.bad() ) {
cout << "Fataler Fehler\n";
} else if( stream.fail()) {
cout << "Fehler bei der Ein-/Ausgabe\n";
if( stream.eof()) {
cout << "Ende des Datenstroms erreicht\n";
}
}
stream.clear();
}
int main() {
int val=0;
cout << "Wert eingeben: ";
cin >> val;
checkIOstate( cin );
std::ifstream file;
file.open("nichtvorhanden.text");
checkIOstate(file);
std::fstream fstr;
fstr.open("neueDatei.txt",
ofstream::out | ofstream::in
| ofstream::binary | ofstream::trunc);
fstr << "Text in der Datei\n";
fstr.seekp(std::ios_base::beg);
char ch;
while( fstr.good()) {
fstr.get(ch);
if(fstr.good()) cout.put(ch);
}
checkIOstate(fstr);
}
Listing 27.4: Operator »bool« von Streams
Book listing lst-0859-book.cpp:
// https://godbolt.org/z/Mr6E3Ez48
#include <iostream>
int main() {
unsigned int val;
std::cout << "Wert eingeben: ";
std::cin >> val;
if( std::cin ) { // operator bool()
/* ... */ // Eingabe korrekt
} else {
std::cout << "Fehler bei std::cin\n"; // Fehler bei der Eingabe
}
}
Godbolt Listing lst-0859-godb.cpp, https://godbolt.org/z/Mr6E3Ez48:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Mr6E3Ez48
#include <iostream>
int main() {
unsigned int val;
std::cout << "Wert eingeben: ";
std::cin >> val;
if( std::cin ) { // operator bool()
/* ... */ // Eingabe korrekt
} else {
std::cout << "Fehler bei std::cin\n"; // Fehler bei der Eingabe
}
}
Listing 27.5: Einen Boolean als Text oder Zahl ausgeben
Book listing lst-0860-book.cpp:
// https://godbolt.org/z/s1csa51z9
#include <iostream>
#include <iomanip>
using std::cin; using std::cout; using std::endl;
void f(bool b) {
cout << b << endl; // Ausgabe: true
}
int main () {
bool b=true;
cout << std::boolalpha << b << endl; // Ausgabe: true
b=false;
cout << b << endl; // Ausgabe: false
f(true);
cout << std::noboolalpha << b << endl; // Ausgabe: 0
b=true;
cout << b << endl; // Ausgabe: 1
}
Godbolt Listing lst-0860-godb.cpp, https://godbolt.org/z/s1csa51z9:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/s1csa51z9
#include <iostream>
#include <iomanip>
using std::cin; using std::cout; using std::endl;
void f(bool b) {
cout << b << endl; // Ausgabe: true
}
int main () {
bool b=true;
cout << std::boolalpha << b << endl; // Ausgabe: true
b=false;
cout << b << endl; // Ausgabe: false
f(true);
cout << std::noboolalpha << b << endl; // Ausgabe: 0
b=true;
cout << b << endl; // Ausgabe: 1
}
Listing 27.6: Zahlenformate bei der Ausgabe
Book listing lst-0862-book.cpp:
// https://godbolt.org/z/bEKaYdssE
#include <iostream>
#include <ios>
using std::cout; using std::endl;
void f() {
int val = 100;
cout << val << endl; // Ausgabe: 0x64
}
int main() {
int val = 255;
cout << std::showbase;
cout << std::dec << val << endl; // Ausgabe: 255
cout << std::hex << val << endl; // Ausgabe: 0xff
f();
cout << std::oct << val << endl; // Ausgabe: 0377
cout << val << std::endl; // Ausgabe: 0377
}
Godbolt Listing lst-0862-godb.cpp, https://godbolt.org/z/bEKaYdssE:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/bEKaYdssE
#include <iostream>
#include <ios>
using std::cout; using std::endl;
void f() {
int val = 100;
cout << val << endl; // Ausgabe: 0x64
}
int main() {
int val = 255;
cout << std::showbase;
cout << std::dec << val << endl; // Ausgabe: 255
cout << std::hex << val << endl; // Ausgabe: 0xff
f();
cout << std::oct << val << endl; // Ausgabe: 0377
cout << val << std::endl; // Ausgabe: 0377
}
Listing 27.7: Unterschiedliche Möglichkeiten zum Auffüllen bei der Ausgabe
Book listing lst-0863-book.cpp:
// https://godbolt.org/z/TMdzrjvhd
#include <iostream>
#include <ios> // left, right, internal
#include <iomanip> // setw
using std::cout; using std::endl;
int main() {
int val = -1000;
cout << std::setw(10) << std::internal
<< val << endl;
cout << std::setw(10) << std::left << val << endl;
cout << std::setw(10) << std::right
<< val << endl;
}
Godbolt Listing lst-0863-godb.cpp, https://godbolt.org/z/TMdzrjvhd:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/TMdzrjvhd
#include <iostream>
#include <ios> // left, right, internal
#include <iomanip> // setw
using std::cout; using std::endl;
int main() {
int val = -1000;
cout << std::setw(10) << std::internal
<< val << endl;
cout << std::setw(10) << std::left << val << endl;
cout << std::setw(10) << std::right
<< val << endl;
}
Listing 27.8: Zahlenformate bei der Ausgabe
Book listing lst-0864-book.cpp:
// https://godbolt.org/z/sYK8oT33x
#include <iostream>
#include <ios> // left, right, internal
#include <iomanip> // setw
using std::cout; using std::endl;
int main() {
double dval = 3.14159;
std::ios_base::fmtflags ff(std::ios::scientific|std::ios::uppercase);
cout << std::setiosflags(ff);
cout << dval << endl; // Ausgabe: 3.141590E+00
cout << std::resetiosflags(ff) << dval << endl; // Ausgabe: 3.14159
cout << std::setprecision(3) << dval << endl; // Ausgabe: 3.14
cout << std::setw(10);
cout << std::setfill( '*' ) << 1246 << endl; // Ausgabe: ******1246
}
Godbolt Listing lst-0864-godb.cpp, https://godbolt.org/z/sYK8oT33x:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/sYK8oT33x
#include <iostream>
#include <ios> // left, right, internal
#include <iomanip> // setw
using std::cout; using std::endl;
int main() {
double dval = 3.14159;
std::ios_base::fmtflags ff(std::ios::scientific|std::ios::uppercase);
cout << std::setiosflags(ff);
cout << dval << endl; // Ausgabe: 3.141590E+00
cout << std::resetiosflags(ff) << dval << endl; // Ausgabe: 3.14159
cout << std::setprecision(3) << dval << endl; // Ausgabe: 3.14
cout << std::setw(10);
cout << std::setfill( '*' ) << 1246 << endl; // Ausgabe: ******1246
}
Listing 27.9: Eigene Manipulatoren
Book listing lst-0865-book.cpp:
// https://godbolt.org/z/TY9df9sb6
#include <iostream>
#include <ios> // left, right, internal
#include <iomanip> // setw
using std::cout; using std::cin; using std::endl;
std::ostream& tabl(std::ostream& os) {
os << '\t';
return os;
}
std::istream& firstNum(std::istream& is) {
char ch;
is.get(ch);
if( (ch >= '0') && (ch <= '9') ) {
std::cin.putback(ch);
}
return is;
}
int main() {
int val=0;
cout << "Text1" << tabl << "Text2" << endl; // Ausgabe: Text1 (tab) Text2
cout << "Eingabe machen: ";
cin >> firstNum >> val;
cout << val << std::endl; // Ausgabe: 12345
}
Godbolt Listing lst-0865-godb.cpp, https://godbolt.org/z/TY9df9sb6:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/TY9df9sb6
#include <iostream>
#include <ios> // left, right, internal
#include <iomanip> // setw
using std::cout; using std::cin; using std::endl;
std::ostream& tabl(std::ostream& os) {
os << '\t';
return os;
}
std::istream& firstNum(std::istream& is) {
char ch;
is.get(ch);
if( (ch >= '0') && (ch <= '9') ) {
std::cin.putback(ch);
}
return is;
}
int main() {
int val=0;
cout << "Text1" << tabl << "Text2" << endl; // Ausgabe: Text1 (tab) Text2
cout << "Eingabe machen: ";
cin >> firstNum >> val;
cout << val << std::endl; // Ausgabe: 12345
}
Listing 27.10: Manipulator als Lambda
Book listing lst-0867-book.cpp:
#include <iostream>
using std::cout; using std::endl;
int main() {
auto ddash = [](auto &os) -> std::ostream& { return os << "-"; };
cout << "Text1" << ddash << "Text2" << endl; // Ausgabe: Text1-Text2
}
Listing 27.11: Manipulator mit Parameter
Book listing lst-0868-book.cpp:
// https://godbolt.org/z/KKE6nWT49
#include <iostream>
using std::cout; using std::endl;
class dendl { // Punkte gefolgt von Newline
int dendl_;
public:
dendl(int n=1)
: dendl_{n} {}
std::ostream& operator()(std::ostream& os) const { // Funktor
for(int i=0; i<dendl_; ++i) os << '.';
return os << '\n';
}
};
std::ostream& operator<<( std::ostream& os, const dendl& elem) {
return elem(os);
}
int main() {
cout << "Text1" << dendl(4); // Ausgabe: Text1....
cout << "Text2" << dendl(2); // Ausgabe: Text2..
cout << "Text3" << dendl(); // Ausgabe: Text3.
}
Godbolt Listing lst-0868-godb.cpp, https://godbolt.org/z/KKE6nWT49:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/KKE6nWT49
#include <iostream>
using std::cout; using std::endl;
class dendl { // Punkte gefolgt von Newline
int dendl_;
public:
dendl(int n=1)
: dendl_{n} {}
std::ostream& operator()(std::ostream& os) const { // Funktor
for(int i=0; i<dendl_; ++i) os << '.';
return os << '\n';
}
};
std::ostream& operator<<( std::ostream& os, const dendl& elem) {
return elem(os);
}
int main() {
cout << "Text1" << dendl(4); // Ausgabe: Text1....
cout << "Text2" << dendl(2); // Ausgabe: Text2..
cout << "Text3" << dendl(); // Ausgabe: Text3.
}
Listing 27.12: Format direkt beeinflussen
Book listing lst-0870-book.cpp:
// https://godbolt.org/z/csbPMYM19
#include <iostream>
#include <ios> // hex, dec
using std::cout; using std::endl;
int main() {
int val = 255;
cout << std::showbase << std::hex << val << endl; // Ausgabe: 0xff
cout << std::noshowbase << std::dec << val << endl; // Ausgabe: 255
}
Godbolt Listing lst-0870-godb.cpp, https://godbolt.org/z/csbPMYM19:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/csbPMYM19
#include <iostream>
#include <ios> // hex, dec
using std::cout; using std::endl;
int main() {
int val = 255;
cout << std::showbase << std::hex << val << endl; // Ausgabe: 0xff
cout << std::noshowbase << std::dec << val << endl; // Ausgabe: 255
}
Listing 27.13: Format mit »setf« und »unsetf« beeinflussen
Book listing lst-0871-book.cpp:
// https://godbolt.org/z/1xzzMdjdM
#include <iostream>
using std::cout; using std::endl;
int main() {
int val = 255;
cout.setf(std::ios_base::hex, std::ios_base::basefield);
cout.setf(std::ios_base::showbase);
cout << val << std::endl; // Ausgabe: 0xff
cout.unsetf(std::ios_base::showbase);
cout.setf(std::ios_base::dec, std::ios_base::basefield);
cout << val << std::endl; // Ausgabe: 255
}
Godbolt Listing lst-0871-godb.cpp, https://godbolt.org/z/1xzzMdjdM:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/1xzzMdjdM
#include <iostream>
using std::cout; using std::endl;
int main() {
int val = 255;
cout.setf(std::ios_base::hex, std::ios_base::basefield);
cout.setf(std::ios_base::showbase);
cout << val << std::endl; // Ausgabe: 0xff
cout.unsetf(std::ios_base::showbase);
cout.setf(std::ios_base::dec, std::ios_base::basefield);
cout << val << std::endl; // Ausgabe: 255
}
Listing 27.14: Flags sichern und wiederherstellen
Book listing lst-0872-book.cpp:
// https://godbolt.org/z/4MY1Yznv9
#include <iostream>
using std::cout; using std::endl;
int main() {
int val = 255;
std::ios::fmtflags ff = std::cout.flags();
cout.flags(std::ios::hex | std::ios::showbase);
cout << val << endl; // Ausgabe: 0xff
cout.flags(ff);
cout << val << endl; // Ausgabe: 255
}
Godbolt Listing lst-0872-godb.cpp, https://godbolt.org/z/4MY1Yznv9:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/4MY1Yznv9
#include <iostream>
using std::cout; using std::endl;
int main() {
int val = 255;
std::ios::fmtflags ff = std::cout.flags();
cout.flags(std::ios::hex | std::ios::showbase);
cout << val << endl; // Ausgabe: 0xff
cout.flags(ff);
cout << val << endl; // Ausgabe: 255
}
Listing 27.15: Öffnen und Anlegen von Dateien
Book listing lst-0873-book.cpp:
// https://godbolt.org/z/EfEx8fdGo
#include <fstream>
#include <iostream>
#include <string>
int main() {
std::string name = "textfile.txt";
std::ifstream file01;
file01.open(name);
if( file01.fail() ) {
std::cout << "Konnte " << name << " nicht oeffnen\n";
}
std::ofstream file02("data.dat");
if( file02.good() ) {
std::cout << "data.dat geoeffnet bzw. erzeugt\n";
}
std::fstream file03;
file03.open("database.db");
if( !file03 ) {
std::cout << "Konnte database.db nicht oeffnen\n";
}
}
Godbolt Listing lst-0873-godb.cpp, https://godbolt.org/z/EfEx8fdGo:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/EfEx8fdGo
#include <fstream>
#include <iostream>
#include <string>
int main() {
std::string name = "textfile.txt";
std::ifstream file01;
file01.open(name);
if( file01.fail() ) {
std::cout << "Konnte " << name << " nicht oeffnen\n";
}
std::ofstream file02("data.dat");
if( file02.good() ) {
std::cout << "data.dat geoeffnet bzw. erzeugt\n";
}
std::fstream file03;
file03.open("database.db");
if( !file03 ) {
std::cout << "Konnte database.db nicht oeffnen\n";
}
}
Listing 27.16: Weitere Flags beim Öffnen von Dateien
Book listing lst-0874-book.cpp:
// https://godbolt.org/z/3ocr4v745
#include <fstream>
#include <iostream>
using std::cout;
int main() {
std::ofstream file01("testfile.txt", std::ios::out|std::ios::app);
if(file01.fail()) {
cout << "Konnte testfile.txt nicht öffnen\n";
} else {
cout << "ok.\n";
}
std::fstream file02;
file02.open("database.db", std::ios::out|std::ios::trunc);
if( !file02 ) {
cout << "Konnte database.db nicht öffnen\n";
} else {
cout << "ok.\n";
}
}
Godbolt Listing lst-0874-godb.cpp, https://godbolt.org/z/3ocr4v745:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/3ocr4v745
#include <fstream>
#include <iostream>
using std::cout;
int main() {
std::ofstream file01("testfile.txt", std::ios::out|std::ios::app);
if(file01.fail()) {
cout << "Konnte testfile.txt nicht öffnen\n";
} else {
cout << "ok.\n";
}
std::fstream file02;
file02.open("database.db", std::ios::out|std::ios::trunc);
if( !file02 ) {
cout << "Konnte database.db nicht öffnen\n";
} else {
cout << "ok.\n";
}
}
Listing 27.17: Explizites Schließen eines Dateistreams
Book listing lst-0875-book.cpp:
// https://godbolt.org/z/arKsG6vqc
#include <fstream>
#include <iostream>
int main() {
std::ofstream file01("data.db");
if( file01.fail() ) {
std::cout << "Konnte data.db nicht öffnen\n";
} else {
std::cout << "ok.\n";
}
file01 << "Text für die Datei\n";
if( file01.is_open()) {
file01.close();
}
file01.open("data001.db");
// Automatisch:
{
std::ofstream file02("data002.db");
} // ab hier wird file02 geschlossen
} // ab hier ist auch file01 geschlossen
Godbolt Listing lst-0875-godb.cpp, https://godbolt.org/z/arKsG6vqc:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/arKsG6vqc
#include <fstream>
#include <iostream>
int main() {
std::ofstream file01("data.db");
if( file01.fail() ) {
std::cout << "Konnte data.db nicht öffnen\n";
} else {
std::cout << "ok.\n";
}
file01 << "Text für die Datei\n";
if( file01.is_open()) {
file01.close();
}
file01.open("data001.db");
// Automatisch:
{
std::ofstream file02("data002.db");
} // ab hier wird file02 geschlossen
} // ab hier ist auch file01 geschlossen
Listing 27.18: Lesen und Schreiben mit Dateien
Book listing lst-0876-book.cpp:
// https://godbolt.org/z/KzsPfMbnq
#include <fstream>
#include <iomanip> // setw
#include <iostream>
int main() {
std::ofstream file("data.dat");
if( !file ) {
std::cout << "Konnte data.dat nicht öffnen\n";
return 1;
}
file << std::setw(10) << std::setfill( '*' )
<< 1234 << std::endl;
}
Godbolt Listing lst-0876-godb.cpp, https://godbolt.org/z/KzsPfMbnq:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/KzsPfMbnq
#include <fstream>
#include <iomanip> // setw
#include <iostream>
int main() {
std::ofstream file("data.dat");
if( !file ) {
std::cout << "Konnte data.dat nicht öffnen\n";
return 1;
}
file << std::setw(10) << std::setfill( '*' )
<< 1234 << std::endl;
}
Listing 27.19: Byteweises Lesen und Schreiben
Book listing lst-0877-book.cpp:
// https://godbolt.org/z/43E38b6Eq
#include <fstream>
#include <iomanip> // setw
#include <iostream>
int main() {
std::ifstream file("data.dat");
if( !file ) {
std::cout << "Fehler beim Öffnen\n";
return 1;
}
char ch;
while(file.get(ch) ) {
std::cout.put(ch);
}
if( file.eof() ) {
file.clear();
}
file.close();
}
Godbolt Listing lst-0877-godb.cpp, https://godbolt.org/z/43E38b6Eq:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/43E38b6Eq
#include <fstream>
#include <iomanip> // setw
#include <iostream>
int main() {
std::ifstream file("data.dat");
if( !file ) {
std::cout << "Fehler beim Öffnen\n";
return 1;
}
char ch;
while(file.get(ch) ) {
std::cout.put(ch);
}
if( file.eof() ) {
file.clear();
}
file.close();
}
Listing 27.20: Eine Datei byteweise kopieren
Book listing lst-0878-book.cpp:
#include <fstream>
#include <iostream>
using std::cout;
int main() {
std::ifstream file("data.dat");
if( !file ) { /* Fehler */ cout << "ERR\n"; return 1; }
std::ofstream filecopy("backup.dat");
if( !filecopy ) { /* Fehler */ cout << "ERR\n"; return 1; }
char ch;
while(file.get(ch) ) {
filecopy.put(ch);
}
}
Listing 27.21: Zeilenweises Lesen und Schreiben
Book listing lst-0879-book.cpp:
// https://godbolt.org/z/7r8r31K3e
#include <fstream>
#include <iostream>
using std::cout;
int main() {
std::ifstream file("44fstream07.cpp");
if( !file ) { /* Fehler */ cout << "ERR\n"; return 1; }
std::ofstream filecopy("backup.cpp");
if( !filecopy ) { /* Fehler */ cout << "ERR\n"; return 1; }
std::string puffer;
while( getline(file, puffer) ) {
filecopy << puffer << std::endl;
cout << puffer << std::endl;
}
if( file.eof() ) {
file.clear();
}
}
Godbolt Listing lst-0879-godb.cpp, https://godbolt.org/z/7r8r31K3e:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/7r8r31K3e
#include <fstream>
#include <iostream>
using std::cout;
int main() {
std::ifstream file("44fstream07.cpp");
if( !file ) { /* Fehler */ cout << "ERR\n"; return 1; }
std::ofstream filecopy("backup.cpp");
if( !filecopy ) { /* Fehler */ cout << "ERR\n"; return 1; }
std::string puffer;
while( getline(file, puffer) ) {
filecopy << puffer << std::endl;
cout << puffer << std::endl;
}
if( file.eof() ) {
file.clear();
}
}
Listing 27.22: Blockweises Lesen und Schreiben mit »read« und »write«
Book listing lst-0880-book.cpp:
// https://godbolt.org/z/qP8cT5n7c
#include <fstream>
#include <iostream>
#include <vector>
using std::cout;
int main() {
std::ifstream file("testfile.txt", std::ios::binary);
if( !file ) { /* Fehler */ cout <<"ERR1\n"; return 1; }
std::ofstream filecopy("backup.dat", std::ios::binary);
if( !filecopy ) { /* Fehler */ return 1; }
file.seekg(0, std::ios::end);
auto size = file.tellg();
cout << "Dateigroesse : " << size << " Byte\n";
file.seekg(0, std::ios::beg); // Wichtig!
std::vector<char> puffer(size);
file.read(puffer.data(), size);
if( !file ) { cout << "Fehler bei read...\n"; return 1;}
cout << "Gelesen: " << file.gcount() << " Byte\n";
filecopy.write( puffer.data(), size );
if( !filecopy ) { cout << "Fehler bei write...\n"; return 1;}
}
Godbolt Listing lst-0880-godb.cpp, https://godbolt.org/z/qP8cT5n7c:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/qP8cT5n7c
#include <fstream>
#include <iostream>
#include <vector>
using std::cout;
int main() {
std::ifstream file("testfile.txt", std::ios::binary);
if( !file ) { /* Fehler */ cout <<"ERR1\n"; return 1; }
std::ofstream filecopy("backup.dat", std::ios::binary);
if( !filecopy ) { /* Fehler */ return 1; }
file.seekg(0, std::ios::end);
auto size = file.tellg();
cout << "Dateigroesse : " << size << " Byte\n";
file.seekg(0, std::ios::beg); // Wichtig!
std::vector<char> puffer(size);
file.read(puffer.data(), size);
if( !file ) { cout << "Fehler bei read...\n"; return 1;}
cout << "Gelesen: " << file.gcount() << " Byte\n";
filecopy.write( puffer.data(), size );
if( !filecopy ) { cout << "Fehler bei write...\n"; return 1;}
}
Listing 27.23: Blockweises Lesen und Schreiben mit Hilfsklasse
Book listing lst-0881-book.cpp:
// https://godbolt.org/z/b3W48s86z
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
using std::cout; using std::string;
class DataClass {
std::string text_;
int data_;
public:
DataClass(string t="", int i=0)
: text_{t}, data_{i} {}
std::ostream& write(std::ostream& os) const {
os << text_ << std::ends;
os.write(reinterpret_cast<const char*>(&data_), sizeof(data_));
return os;
}
std::istream& read(std::istream& is) {
std::getline(is, text_, '\0');
is.read(reinterpret_cast<char*>(&data_), sizeof(data_));
return is;
}
std::ostream& print(std::ostream& os) {
return os << text_ << " : " << data_ << std::endl;
}
};
int main() {
std::ofstream file_w("data.dat", std::ios::binary);
if( !file_w) { cout << "Fehler bei Öffnen\n"; return 1; }
std::vector<DataClass> vec_dat;
vec_dat.push_back(DataClass("Ein Text", 123));
vec_dat.push_back(DataClass("Mehr Text", 321));
vec_dat.emplace_back("Viel mehr Text", 333);
for(const auto &elem : vec_dat){
elem.write(file_w);
}
file_w.close();
std::ifstream file_r("data.dat", std::ios::binary);
if( !file_r) { cout << "Fehler bei Öffnen\n"; return 1; }
DataClass dat_r;
while( file_r ) {
dat_r.read(file_r);
if( file_r.eof()) break;
dat_r.print(cout);
}
}
Godbolt Listing lst-0881-godb.cpp, https://godbolt.org/z/b3W48s86z:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/b3W48s86z
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
using std::cout; using std::string;
class DataClass {
std::string text_;
int data_;
public:
DataClass(string t="", int i=0)
: text_{t}, data_{i} {}
std::ostream& write(std::ostream& os) const {
os << text_ << std::ends;
os.write(reinterpret_cast<const char*>(&data_), sizeof(data_));
return os;
}
std::istream& read(std::istream& is) {
std::getline(is, text_, '\0');
is.read(reinterpret_cast<char*>(&data_), sizeof(data_));
return is;
}
std::ostream& print(std::ostream& os) {
return os << text_ << " : " << data_ << std::endl;
}
};
int main() {
std::ofstream file_w("data.dat", std::ios::binary);
if( !file_w) { cout << "Fehler bei Öffnen\n"; return 1; }
std::vector<DataClass> vec_dat;
vec_dat.push_back(DataClass("Ein Text", 123));
vec_dat.push_back(DataClass("Mehr Text", 321));
vec_dat.emplace_back("Viel mehr Text", 333);
for(const auto &elem : vec_dat){
elem.write(file_w);
}
file_w.close();
std::ifstream file_r("data.dat", std::ios::binary);
if( !file_r) { cout << "Fehler bei Öffnen\n"; return 1; }
DataClass dat_r;
while( file_r ) {
dat_r.read(file_r);
if( file_r.eof()) break;
dat_r.print(cout);
}
}
Listing 27.24: Ausgaben zwischen Threads mit »osyncstream« synchronisieren
Book listing lst-0883-book.cpp:
// https://godbolt.org/z/dz75jr1rM
#include <iostream>
#include <thread>
#include <syncstream>
long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }
void runFib(long von, long schritt, long bis) {
for (auto n=von; n<=bis; n+=schritt) {
std::osyncstream osync{ std::cout }; // Sync auf cout, solange osync existiert
osync << "fib("<<n<<")=" << fib(n) << '\n';
}
}
int main() {
std::jthread f40{ runFib, 1, 3, 40 };
std::jthread f41{ runFib, 2, 3, 41 };
std::jthread f42{ runFib, 3, 3, 42 };
}
Godbolt Listing lst-0883-godb.cpp, https://godbolt.org/z/dz75jr1rM:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/dz75jr1rM
#include <iostream>
#include <thread>
#include <syncstream>
long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }
void runFib(long von, long schritt, long bis) {
for (auto n=von; n<=bis; n+=schritt) {
std::osyncstream osync{ std::cout }; // Sync auf cout, solange osync existiert
osync << "fib("<<n<<")=" << fib(n) << '\n';
}
}
int main() {
std::jthread f40{ runFib, 1, 3, 40 };
std::jthread f41{ runFib, 2, 3, 41 };
std::jthread f42{ runFib, 3, 3, 42 };
}
Listing 27.25: Schreiben in einen »stringstream«
Book listing lst-0884-book.cpp:
// https://godbolt.org/z/cbGbcT178
#include <sstream> // ostringstream
#include <iostream>
int main() {
std::ostringstream ostr;
double dval = 3.1415;
int ival = 4321;
ostr << dval << " : " << ival;
const std::string sval = ostr.str();
std::cout << sval << std::endl; // Ausgabe: 3.1415 : 4321
}
Godbolt Listing lst-0884-godb.cpp, https://godbolt.org/z/cbGbcT178:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/cbGbcT178
#include <sstream> // ostringstream
#include <iostream>
int main() {
std::ostringstream ostr;
double dval = 3.1415;
int ival = 4321;
ostr << dval << " : " << ival;
const std::string sval = ostr.str();
std::cout << sval << std::endl; // Ausgabe: 3.1415 : 4321
}
Listing 27.26: Lesen aus einem »stringstream«
Book listing lst-0885-book.cpp:
// https://godbolt.org/z/1EMox3hW5
#include <sstream> // istringstream
#include <iostream>
int main() {
std::istringstream istr;
std::string sval("3.1415 : 4321");
std::string none;
double dval=0.0;
int ival=0;
istr.str(sval); // initialisieren
istr >> dval >> none >> ival; // auslesen
if( ! istr.eof() ) {
std::cout << "Fehler beim Konvertieren\n"; return 1;
}
std::cout << dval << " == " << none << " == " << ival << "\n";
// Ausgabe: 3.1415 == : == 4321
}
Godbolt Listing lst-0885-godb.cpp, https://godbolt.org/z/1EMox3hW5:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/1EMox3hW5
#include <sstream> // istringstream
#include <iostream>
int main() {
std::istringstream istr;
std::string sval("3.1415 : 4321");
std::string none;
double dval=0.0;
int ival=0;
istr.str(sval); // initialisieren
istr >> dval >> none >> ival; // auslesen
if( ! istr.eof() ) {
std::cout << "Fehler beim Konvertieren\n"; return 1;
}
std::cout << dval << " == " << none << " == " << ival << "\n";
// Ausgabe: 3.1415 == : == 4321
}
Listing 27.27: Typkonvertierung mittels »stringstream«
Book listing lst-0886-book.cpp:
// https://godbolt.org/z/vs5henTrz
#include <sstream> // stringstream
#include <iostream>
#include <stdexcept> // invalid_argument
template <class T1, class T2>
void myConvert(const T1& in, T2& out) {
std::stringstream ss;
ss << in;
ss >> out;
if( ! ss.eof() ) {
throw std::invalid_argument("Fehler beim Konvertieren");
}
}
int main() {
std::string sval;
float fval=3.1415f;
std::string sdval("5.321");
double dsval=0;
std::string gehtnicht("geht nicht");
try {
myConvert(fval, sval);
std::cout << sval << std::endl; // Ausgabe: 3.1415
myConvert(sdval, dsval);
std::cout << dsval << std::endl; // Ausgabe: 5.321
myConvert(gehtnicht, dsval); // löst "Fehler beim Konvertieren" aus
}
catch(const std::invalid_argument& e) {
std::cout << e.what() << std::endl;
}
}
Godbolt Listing lst-0886-godb.cpp, https://godbolt.org/z/vs5henTrz:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/vs5henTrz
#include <sstream> // stringstream
#include <iostream>
#include <stdexcept> // invalid_argument
template <class T1, class T2>
void myConvert(const T1& in, T2& out) {
std::stringstream ss;
ss << in;
ss >> out;
if( ! ss.eof() ) {
throw std::invalid_argument("Fehler beim Konvertieren");
}
}
int main() {
std::string sval;
float fval=3.1415f;
std::string sdval("5.321");
double dsval=0;
std::string gehtnicht("geht nicht");
try {
myConvert(fval, sval);
std::cout << sval << std::endl; // Ausgabe: 3.1415
myConvert(sdval, dsval);
std::cout << dsval << std::endl; // Ausgabe: 5.321
myConvert(gehtnicht, dsval); // löst "Fehler beim Konvertieren" aus
}
catch(const std::invalid_argument& e) {
std::cout << e.what() << std::endl;
}
}
Listing 27.28: Die Funktion »to_string«
Book listing lst-0887-book.cpp:
// https://godbolt.org/z/z6sYqM48e
#include <iostream>
#include <string>
void show(double f) {
std::cout << "os: " << f
<< "\t to_string: " << std::to_string(f) << "\n";
}
int main() {
show(23.43); // Ausgabe: os: 23.43 to_string: 23.430000
show(1e-9); // Ausgabe: os: 1e-09 to_string: 0.000000
show(1e40); // Ausgabe: os: 1e+40 to_string: 100…0752.000000
show(1e-40); // Ausgabe: os: 1e-40 to_string: 0.000000
show(123456789); // Ausgabe: os: 1.23457e+08 to_string: 123456789.000000
}
Godbolt Listing lst-0887-godb.cpp, https://godbolt.org/z/z6sYqM48e:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/z6sYqM48e
#include <iostream>
#include <string>
void show(double f) {
std::cout << "os: " << f
<< "\t to_string: " << std::to_string(f) << "\n";
}
int main() {
show(23.43); // Ausgabe: os: 23.43 to_string: 23.430000
show(1e-9); // Ausgabe: os: 1e-09 to_string: 0.000000
show(1e40); // Ausgabe: os: 1e+40 to_string: 100…0752.000000
show(1e-40); // Ausgabe: os: 1e-40 to_string: 0.000000
show(123456789); // Ausgabe: os: 1.23457e+08 to_string: 123456789.000000
}
Listing 27.29: Daten aus dem »rdbuf« übertragen
Book listing lst-0890-book.cpp:
// https://godbolt.org/z/on6W73nz1
#include <fstream>
#include <iostream>
#include <memory> // unique_ptr
int main() {
std::fstream file("27Streams.tex"); // Datei zum Lesen öffnen
auto bufptr = file.rdbuf(); // std::streambuf*
auto size = bufptr->pubseekoff(0, file.end); // std::streamsize
bufptr->pubseekoff(0, file.beg); // wieder an den Anfang
auto buffer = std::unique_ptr<char[]>(new char[size]); // Speicher holen
auto n = bufptr->sgetn(buffer.get(), size); // übertrage Anzahl Zeichen
std::cout << "Zeichen gelesen: " << n << "\n";
std::cout.write(buffer.get(), size); // char[] ausgeben
}
Godbolt Listing lst-0890-godb.cpp, https://godbolt.org/z/on6W73nz1:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/on6W73nz1
#include <fstream>
#include <iostream>
#include <memory> // unique_ptr
int main() {
std::fstream file("27Streams.tex"); // Datei zum Lesen öffnen
auto bufptr = file.rdbuf(); // std::streambuf*
auto size = bufptr->pubseekoff(0, file.end); // std::streamsize
bufptr->pubseekoff(0, file.beg); // wieder an den Anfang
auto buffer = std::unique_ptr<char[]>(new char[size]); // Speicher holen
auto n = bufptr->sgetn(buffer.get(), size); // übertrage Anzahl Zeichen
std::cout << "Zeichen gelesen: " << n << "\n";
std::cout.write(buffer.get(), size); // char[] ausgeben
}
Listing 27.30: So fügen Sie Pfade zusammen.
Book listing lst-0892-book.cpp:
// https://godbolt.org/z/1YPT3asMz
#include <filesystem> // std::filesystem
#include <iostream>
namespace fs = std::filesystem; using std::cout; using std::endl;
int main() {
// Pfadkomponenten
fs::path root {"/"};
fs::path dir {"var/www/"};
fs::path index {"index.html"};
// zusammenfügen
fs::path p = root / dir / index; // operator/
// ausgeben
cout << "Name: " << p << endl; // "/var/www/index.html"
// zerlegen
cout << "Vater: " << p.parent_path() << endl; // "/var/www"
cout << "Name: " << p.filename() << endl; // "index.html"
cout << "Endung: " << p.extension() << endl; // ".html"
// Information
cout << std::boolalpha;
cout << "Existiert? " << fs::exists(p) << endl;
cout << "Echte Datei? " << fs::is_regular_file(p) << endl;
}
Godbolt Listing lst-0892-godb.cpp, https://godbolt.org/z/1YPT3asMz:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/1YPT3asMz
#include <filesystem> // std::filesystem
#include <iostream>
namespace fs = std::filesystem; using std::cout; using std::endl;
int main() {
// Pfadkomponenten
fs::path root {"/"};
fs::path dir {"var/www/"};
fs::path index {"index.html"};
// zusammenfügen
fs::path p = root / dir / index; // operator/
// ausgeben
cout << "Name: " << p << endl; // "/var/www/index.html"
// zerlegen
cout << "Vater: " << p.parent_path() << endl; // "/var/www"
cout << "Name: " << p.filename() << endl; // "index.html"
cout << "Endung: " << p.extension() << endl; // ".html"
// Information
cout << std::boolalpha;
cout << "Existiert? " << fs::exists(p) << endl;
cout << "Echte Datei? " << fs::is_regular_file(p) << endl;
}
GodboltId:M8xjcnKxq
Book listing lst-0893-book.cpp:
// https://godbolt.org/z/M8xjcnKxq
#include <format>
#include <chrono>
#include <string>
#include <string_view>
#include <iostream>
using namespace std; using namespace std::literals;
void pr(string_view s) { cout << s << endl; }
double pi = 3.14159265359;
int main() {
pr(format("Hallo, {}!", "Leser")); // einfacher C-String
pr(format("Hallo, {}!", "Autor"s)); // einfacher String
pr(format("Du bist {} Jahre alt.", 30)); // Ganzzahlen
pr(format("Das macht {:.2f} Euro.", 19.9933)); // Fließkommazahl, 2 Stellen
pr(format("Wissenschaftlich: {:e}", -44.876)); // ergibt "-4.487600e+01"
pr(format("Binär von {} ist {:b}.", 42, 42)); // binär ohne Basis
pr(format("Hex von {} ist {:#x}.", 73, 73)); // hexadezimal mit Basis
pr(format("Mit Nullen aufgefüllt: {:03}", 7)); // ergibt "007"
pr(format("|{0:<10}|{1:^10}|{2:>10}|", "li", "mi", "re"));
// Ausrichtung und Index
pr(format("{} {:.9}!", "Boa", "Constrictor")); // ohne Index, String abschneiden
using namespace std::chrono; // schicke Zeitangaben:
pr(format("{}, {}", 2023y/11/5, minutes{20})); // Ausgabe: 2023-11-05, 20min
}
Godbolt Listing lst-0893-godb.cpp, https://godbolt.org/z/M8xjcnKxq:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/M8xjcnKxq
#include <format>
#include <chrono>
#include <string>
#include <string_view>
#include <iostream>
using namespace std; using namespace std::literals;
void pr(string_view s) { cout << s << endl; }
double pi = 3.14159265359;
int main() {
pr(format("Hallo, {}!", "Leser")); // einfacher C-String
pr(format("Hallo, {}!", "Autor"s)); // einfacher String
pr(format("Du bist {} Jahre alt.", 30)); // Ganzzahlen
pr(format("Das macht {:.2f} Euro.", 19.9933)); // Fließkommazahl, 2 Stellen
pr(format("Wissenschaftlich: {:e}", -44.876)); // ergibt "-4.487600e+01"
pr(format("Binär von {} ist {:b}.", 42, 42)); // binär ohne Basis
pr(format("Hex von {} ist {:#x}.", 73, 73)); // hexadezimal mit Basis
pr(format("Mit Nullen aufgefüllt: {:03}", 7)); // ergibt "007"
pr(format("|{0:<10}|{1:^10}|{2:>10}|", "li", "mi", "re"));
// Ausrichtung und Index
pr(format("{} {:.9}!", "Boa", "Constrictor")); // ohne Index, String abschneiden
using namespace std::chrono; // schicke Zeitangaben:
pr(format("{}, {}", 2023y/11/5, minutes{20})); // Ausgabe: 2023-11-05, 20min
}
Listing 27.31: Ein Formatierer kann parsen und formatieren delegieren.
Book listing lst-0894-book.cpp:
// https://godbolt.org/z/jYsbxqzYW
#include <format>
#include <string>
#include <vector>
#include <iostream>
struct Elb {
std::string name;
int geb;
std::string epoche;
std::string volk;
};
template<> struct std::formatter<Elb> {
std::formatter<std::string> sub_fmt;
constexpr auto parse(std::format_parse_context& pctx) {
return sub_fmt.parse(pctx); // liefert iterator auf '}'
}
auto format(const Elb& elb, std::format_context& fctx) const {
std::string s = std::format("{}/{} ({} {})",
elb.name, elb.volk, elb.geb, elb.epoche);
return sub_fmt.format(s, fctx); // formatieren delegieren
}
};
int main() {
std::vector<Elb> elben{
{"Feanor", 1169, "EZ", "Nordor"},
{"Galadriel", 1362, "EZ", "Noldor"},
{"Legolas", 87, "DZ", "Sindar"},
{"Elrond", 532, "EZ", "Halbelb"},
{"Elwe", 1050, "EZ", "Sindar"},
};
for (const auto& e : elben) {
std::cout << std::format("Elb: {:>20}", e) << std::endl;
}
}
Godbolt Listing lst-0894-godb.cpp, https://godbolt.org/z/jYsbxqzYW:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/jYsbxqzYW
#include <format>
#include <string>
#include <vector>
#include <iostream>
struct Elb {
std::string name;
int geb;
std::string epoche;
std::string volk;
};
template<> struct std::formatter<Elb> {
std::formatter<std::string> sub_fmt;
constexpr auto parse(std::format_parse_context& pctx) {
return sub_fmt.parse(pctx); // liefert iterator auf '}'
}
auto format(const Elb& elb, std::format_context& fctx) const {
std::string s = std::format("{}/{} ({} {})",
elb.name, elb.volk, elb.geb, elb.epoche);
return sub_fmt.format(s, fctx); // formatieren delegieren
}
};
int main() {
std::vector<Elb> elben{
{"Feanor", 1169, "EZ", "Nordor"},
{"Galadriel", 1362, "EZ", "Noldor"},
{"Legolas", 87, "DZ", "Sindar"},
{"Elrond", 532, "EZ", "Halbelb"},
{"Elwe", 1050, "EZ", "Sindar"},
};
for (const auto& e : elben) {
std::cout << std::format("Elb: {:>20}", e) << std::endl;
}
}
Listing 27.32: Ein Formatierer kann selbst parsen und ausgeben.
Book listing lst-0895-book.cpp:
// https://godbolt.org/z/WqjK31Gn6
// 'Elb' wie zuvor…
template<> struct std::formatter<Elb> {
std::string attribs; // Folge von '%n', '%g', '%e', '%v' und anderem
constexpr auto parse(std::format_parse_context& pctx) {
auto it = std::ranges::find(pctx.begin(), pctx.end(), '}');// suche '}'
attribs = std::string(pctx.begin(), it); // alles speichern
return it; // zeigt auf '}'
}
auto format(const Elb& elb, std::format_context& fctx) const {
auto out = fctx.out(); // hier hinein
for(auto n=0u; n<attribs.size()-1; ++n) {
if(attribs[n] == '%') { // Instruktion, ein Mitglied auszugeben
switch(attribs[++n]) {
case 'n': out = std::format_to(out, "{}", elb.name); break;
case 'g': out = std::format_to(out, "{}", elb.geb); break;
case 'e': out = std::format_to(out, "{}", elb.epoche); break;
case 'v': out = std::format_to(out, "{}", elb.volk); break;
case '%': out = std::format_to(out, "%"); break; // %% wird zu %
}
} else {
out = std::format_to(out, "{}", attribs[n]); // alles andere
}
}
return out; // zeigt ans Ende
}
};
int main() {
Elb e{"Feanor", 1169, "EZ", "Nordor"};
std::cout << std::format("{:Elb %n}", e) << std::endl;
// Ausgabe: Elb Feanor
std::cout << std::format("Elb {:%n, %v, geboren %g im Zeitalter %e}\n", e);
// Ausgabe: Elb Feanor, Nordor, geboren 1169 im Zeitalter EZ
}
Godbolt Listing lst-0895-godb.cpp, https://godbolt.org/z/WqjK31Gn6:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/WqjK31Gn6
// 'Elb' wie zuvor…
template<> struct std::formatter<Elb> {
std::string attribs; // Folge von '%n', '%g', '%e', '%v' und anderem
constexpr auto parse(std::format_parse_context& pctx) {
auto it = std::ranges::find(pctx.begin(), pctx.end(), '}');// suche '}'
attribs = std::string(pctx.begin(), it); // alles speichern
return it; // zeigt auf '}'
}
auto format(const Elb& elb, std::format_context& fctx) const {
auto out = fctx.out(); // hier hinein
for(auto n=0u; n<attribs.size()-1; ++n) {
if(attribs[n] == '%') { // Instruktion, ein Mitglied auszugeben
switch(attribs[++n]) {
case 'n': out = std::format_to(out, "{}", elb.name); break;
case 'g': out = std::format_to(out, "{}", elb.geb); break;
case 'e': out = std::format_to(out, "{}", elb.epoche); break;
case 'v': out = std::format_to(out, "{}", elb.volk); break;
case '%': out = std::format_to(out, "%"); break; // %% wird zu %
}
} else {
out = std::format_to(out, "{}", attribs[n]); // alles andere
}
}
return out; // zeigt ans Ende
}
};
int main() {
Elb e{"Feanor", 1169, "EZ", "Nordor"};
std::cout << std::format("{:Elb %n}", e) << std::endl;
// Ausgabe: Elb Feanor
std::cout << std::format("Elb {:%n, %v, geboren %g im Zeitalter %e}\n", e);
// Ausgabe: Elb Feanor, Nordor, geboren 1169 im Zeitalter EZ
}
Listing 28.1: So geben Sie mit »pair« zwei Werte gleichzeitig zurück.
Book listing lst-0896-book.cpp:
// https://godbolt.org/z/4YM9d99xG
#include <iostream>
#include <string>
#include <vector>
#include <utility> // pair
using std::pair; using std::cout; using std::cin; using std::string;
std::vector<string> monate { "Jan", "Feb", "Mar" };
std::vector temps { 8, 12, 11 };
std::pair<string, int> monatMitTemp(size_t m) {
auto monat = monate.at(m);
auto temperatur = temps.at(m);
return std::make_pair(monat, temperatur);
}
int main() {
std::pair daten = monatMitTemp(1);
cout << "Monat : " << daten.first << std::endl; // Ausgabe: Monat : Feb
cout << "Temperatur : " << daten.second << std::endl;
// Ausgabe: Temperatur : 12
}
Godbolt Listing lst-0896-godb.cpp, https://godbolt.org/z/4YM9d99xG:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/4YM9d99xG
#include <iostream>
#include <string>
#include <vector>
#include <utility> // pair
using std::pair; using std::cout; using std::cin; using std::string;
std::vector<string> monate { "Jan", "Feb", "Mar" };
std::vector temps { 8, 12, 11 };
std::pair<string, int> monatMitTemp(size_t m) {
auto monat = monate.at(m);
auto temperatur = temps.at(m);
return std::make_pair(monat, temperatur);
}
int main() {
std::pair daten = monatMitTemp(1);
cout << "Monat : " << daten.first << std::endl; // Ausgabe: Monat : Feb
cout << "Temperatur : " << daten.second << std::endl;
// Ausgabe: Temperatur : 12
}
Listing 28.2: Mit »tuple« können Sie beliebig viele Elemente zurückgeben.
Book listing lst-0897-book.cpp:
// https://godbolt.org/z/47jb7nEG4
#include <iostream>
#include <string>
#include <algorithm> // min, max
#include <tuple>
using std::tuple; using std::make_tuple; using std::get; using std::cout;
using std::string;
tuple<int,int,int> ordne(int a, int b, int c) {
using std::min; using std::max;
auto x = min(a,min(b,c));
auto y = max(min(a,b), min(max(a,b),c));
auto z = max(a,max(b,c));
return make_tuple(x, y, z);
}
auto praeser(int jahr) {
using namespace std::literals;
if(jahr>=2017)
return make_tuple("Frank-Walter"s, "Steinmeier"s, "SPD"s, 1956);
if(jahr>=2012)
return make_tuple("Joachim"s, "Gauck"s, "-"s, 1940);
// …
}
int main() {
tuple<int,int,int> zs = ordne(23, 42, 7);
cout << get<0>(zs) <<' '<< get<1>(zs) <<' '<< get<2>(zs) <<'\n';
// Ausgabe: 7 23 42
auto ps = praeser(2015);
cout << get<1>(ps) << '\n'; // Ausgabe: Gauck
}
Godbolt Listing lst-0897-godb.cpp, https://godbolt.org/z/47jb7nEG4:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/47jb7nEG4
#include <iostream>
#include <string>
#include <algorithm> // min, max
#include <tuple>
using std::tuple; using std::make_tuple; using std::get; using std::cout;
using std::string;
tuple<int,int,int> ordne(int a, int b, int c) {
using std::min; using std::max;
auto x = min(a,min(b,c));
auto y = max(min(a,b), min(max(a,b),c));
auto z = max(a,max(b,c));
return make_tuple(x, y, z);
}
auto praeser(int jahr) {
using namespace std::literals;
if(jahr>=2017)
return make_tuple("Frank-Walter"s, "Steinmeier"s, "SPD"s, 1956);
if(jahr>=2012)
return make_tuple("Joachim"s, "Gauck"s, "-"s, 1940);
// …
}
int main() {
tuple<int,int,int> zs = ordne(23, 42, 7);
cout << get<0>(zs) <<' '<< get<1>(zs) <<' '<< get<2>(zs) <<'\n';
// Ausgabe: 7 23 42
auto ps = praeser(2015);
cout << get<1>(ps) << '\n'; // Ausgabe: Gauck
}
Listing 28.3: »get« funktioniert mit einem Typ als Index.
Book listing lst-0898-book.cpp:
// https://godbolt.org/z/cx8b9seaW
// … wie zuvor …
int main() {
tuple ps = praeser(2015);
cout << get<int>(ps) << '\n'; // Ausgabe: 1940
cout << get<string>(ps) << '\n'; // (ERR) nicht eindeutig
}
Godbolt Listing lst-0898-godb.cpp, https://godbolt.org/z/cx8b9seaW:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/cx8b9seaW
// … wie zuvor …
int main() {
tuple ps = praeser(2015);
cout << get<int>(ps) << '\n'; // Ausgabe: 1940
cout << get<string>(ps) << '\n'; // (ERR) nicht eindeutig
}
Listing 28.4: Tupel zerlegen mit »tie« und »ignore«
Book listing lst-0899-book.cpp:
// https://godbolt.org/z/YzTvoE3x6
// … wie zuvor …
int main() {
using std::tie; using std::ignore;
string nachname {};
int gebj {};
tie(ignore, nachname, ignore, gebj) = praeser(2015);
cout << nachname << ' ' << gebj << '\n'; // Ausgabe: Gauck 1940
}
Godbolt Listing lst-0899-godb.cpp, https://godbolt.org/z/YzTvoE3x6:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/YzTvoE3x6
// … wie zuvor …
int main() {
using std::tie; using std::ignore;
string nachname {};
int gebj {};
tie(ignore, nachname, ignore, gebj) = praeser(2015);
cout << nachname << ' ' << gebj << '\n'; // Ausgabe: Gauck 1940
}
Listing 28.5: Tupel implementieren lexikografische Ordnung.
Book listing lst-0900-book.cpp:
// https://godbolt.org/z/jrP4v76aj
#include <iostream>
#include <string>
#include <tuple>
#include <vector>
#include <algorithm> // ranges::sort
using std::tuple; using std::get; using std::cout; using std::string;
int main() {
std::vector<tuple<string,string,int>> armstrongs =
{ {"Armstrong", "Louis", 1901} // Initialisieren per Initialisierungsliste
, {"Armstrong", "Lance", 1971}
, {"Armstrong", "Neil", 1930} };
std::ranges::sort(armstrongs); // Lance < Louis < Neil
for(const auto& a : armstrongs) {
cout << get<0>(a) << ", " << get<1>(a) << ", " << get<2>(a) << "\n";
}
}
Godbolt Listing lst-0900-godb.cpp, https://godbolt.org/z/jrP4v76aj:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/jrP4v76aj
#include <iostream>
#include <string>
#include <tuple>
#include <vector>
#include <algorithm> // ranges::sort
using std::tuple; using std::get; using std::cout; using std::string;
int main() {
std::vector<tuple<string,string,int>> armstrongs =
{ {"Armstrong", "Louis", 1901} // Initialisieren per Initialisierungsliste
, {"Armstrong", "Lance", 1971}
, {"Armstrong", "Neil", 1930} };
std::ranges::sort(armstrongs); // Lance < Louis < Neil
for(const auto& a : armstrongs) {
cout << get<0>(a) << ", " << get<1>(a) << ", " << get<2>(a) << "\n";
}
}
Listing 28.6: Tupel als Schlüssel
Book listing lst-0901-book.cpp:
// https://godbolt.org/z/9qhMo6zbb
#include <iostream>
#include <string>
#include <tuple>
#include <map>
#include <unordered_set>
using std::tuple; using std::get; using std::cout; using std::string;
int main() {
std::map<tuple<int,string>,double> m { {{12,"x"},3.14} };
cout << m[{12,"x"}] << "\n"; // Ausgabe: 3.14
std::unordered_set<tuple<int,string>> s { {12,"x"} }; // (ERR) kein std::hash
}
Godbolt Listing lst-0901-godb.cpp, https://godbolt.org/z/9qhMo6zbb:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/9qhMo6zbb
#include <iostream>
#include <string>
#include <tuple>
#include <map>
#include <unordered_set>
using std::tuple; using std::get; using std::cout; using std::string;
int main() {
std::map<tuple<int,string>,double> m { {{12,"x"},3.14} };
cout << m[{12,"x"}] << "\n"; // Ausgabe: 3.14
std::unordered_set<tuple<int,string>> s { {12,"x"} }; // (ERR) kein std::hash
}
Listing 28.7: Tupel als Schlüssel
Book listing lst-0902-book.cpp:
// https://godbolt.org/z/vdT7TTjWK
#include <iostream>
#include <string>
#include <tuple>
#include <map>
#include <unordered_set>
using std::tuple; using std::tie; using std::cout; using std::string;
struct Point {
int x,y,z;
bool operator<(const Point &b) {
return tie(x,y,z) < tie(b.x, b.y, b.z);
}
};
int main() {
Point a{ 11, 22, 33 };
Point b{ 11, 33, 0 };
cout << std::boolalpha << (a < b) << "\n"; // Ausgabe: true
}
Godbolt Listing lst-0902-godb.cpp, https://godbolt.org/z/vdT7TTjWK:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/vdT7TTjWK
#include <iostream>
#include <string>
#include <tuple>
#include <map>
#include <unordered_set>
using std::tuple; using std::tie; using std::cout; using std::string;
struct Point {
int x,y,z;
bool operator<(const Point &b) {
return tie(x,y,z) < tie(b.x, b.y, b.z);
}
};
int main() {
Point a{ 11, 22, 33 };
Point b{ 11, 33, 0 };
cout << std::boolalpha << (a < b) << "\n"; // Ausgabe: true
}
Listing 28.8: Mehrere kleine Tupel zu einem großen zusammenfügen
Book listing lst-0903-book.cpp:
// https://godbolt.org/z/eq1dqWbe9
#include <iostream>
#include <string>
#include <tuple>
using std::tuple; using std::cout; using std::string;
int main() {
tuple<int,string> a { 12, "gnorf" };
tuple b { 666 };
tuple<double,double,string> c { 77.77, 33.33, "frong" };
tuple<int,string,int,double,double,string> r = std::tuple_cat( a, b, c );
cout << std::get<2>(r) << "\n"; // Ausgabe: 666
}
Godbolt Listing lst-0903-godb.cpp, https://godbolt.org/z/eq1dqWbe9:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/eq1dqWbe9
#include <iostream>
#include <string>
#include <tuple>
using std::tuple; using std::cout; using std::string;
int main() {
tuple<int,string> a { 12, "gnorf" };
tuple b { 666 };
tuple<double,double,string> c { 77.77, 33.33, "frong" };
tuple<int,string,int,double,double,string> r = std::tuple_cat( a, b, c );
cout << std::get<2>(r) << "\n"; // Ausgabe: 666
}
Listing 28.9: Nützliche Tuple-Type-Traits
Book listing lst-0904-book.cpp:
// https://godbolt.org/z/Psdz9s9Gc
#include <iostream>
#include <string>
#include <tuple>
using namespace std;
template<typename Tuple>
auto back(Tuple &&tuple) {
using Noref = typename remove_reference<Tuple>::type; // falls Tuple&
constexpr auto sz = tuple_size<Noref>::value;
return get<sz-1>(forward<Tuple>(tuple));
}
int main() {
tuple<string,int,string> enterprise = make_tuple("NCC", 1701, "D");
cout << back(enterprise) << "\n"; // Ausgabe: D
}
Godbolt Listing lst-0904-godb.cpp, https://godbolt.org/z/Psdz9s9Gc:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Psdz9s9Gc
#include <iostream>
#include <string>
#include <tuple>
using namespace std;
template<typename Tuple>
auto back(Tuple &&tuple) {
using Noref = typename remove_reference<Tuple>::type; // falls Tuple&
constexpr auto sz = tuple_size<Noref>::value;
return get<sz-1>(forward<Tuple>(tuple));
}
int main() {
tuple<string,int,string> enterprise = make_tuple("NCC", 1701, "D");
cout << back(enterprise) << "\n"; // Ausgabe: D
}
Listing 28.10: Übereinstimmung, Suche und Aufzählung mit regulären Ausdrücken
Book listing lst-0905-book.cpp:
// https://godbolt.org/z/zjboebEhc
#include <string>
#include <iostream>
#include <regex>
using std::regex; using std::sregex_iterator; using std::string;
const regex rgxMobile(R"(01[567]\d{6,10})"); // Handy 0151-0179
bool isMobilephone(const string& text) {
return std::regex_match(text, rgxMobile); // Passt text ganz?
}
bool containsMobilephone(const string &text) {
return std::regex_search(text, rgxMobile); // irgendwo in text?
}
void listMobilephones(const string &text) {
sregex_iterator begin{ text.cbegin(), text.cend(), rgxMobile };
sregex_iterator end;
for(auto it = begin; it != end; ++it)
std::cout << it->str() << " "; // Treffertext
} // "xyz01709999 abc 0161887766 uvw" -> "01709999 161887766"
Godbolt Listing lst-0905-godb.cpp, https://godbolt.org/z/zjboebEhc:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/zjboebEhc
#include <string>
#include <iostream>
#include <regex>
using std::regex; using std::sregex_iterator; using std::string;
const regex rgxMobile(R"(01[567]\d{6,10})"); // Handy 0151-0179
bool isMobilephone(const string& text) {
return std::regex_match(text, rgxMobile); // Passt text ganz?
}
bool containsMobilephone(const string &text) {
return std::regex_search(text, rgxMobile); // irgendwo in text?
}
void listMobilephones(const string &text) {
sregex_iterator begin{ text.cbegin(), text.cend(), rgxMobile };
sregex_iterator end;
for(auto it = begin; it != end; ++it)
std::cout << it->str() << " "; // Treffertext
} // "xyz01709999 abc 0161887766 uvw" -> "01709999 161887766"
Listing 28.11: Suche und Übereinstimmung
Book listing lst-0906-book.cpp:
// https://godbolt.org/z/E9hcWGMW4
#include <regex>
#include <string>
#include <iostream>
using std::regex; using std::regex_match; using std::regex_search;
int main() {
std::cout << std::boolalpha;
regex muster {"ello"};
std::string text = "Hello world";
auto b1 = regex_match (text.cbegin(), text.cend(), muster); // passt nicht
std::cout << b1 << "\n"; // Ausgabe: false
auto b2 = regex_search(text.cbegin(), text.cend(), muster); // gefunden
std::cout << b2 << "\n"; // Ausgabe: true
}
Godbolt Listing lst-0906-godb.cpp, https://godbolt.org/z/E9hcWGMW4:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/E9hcWGMW4
#include <regex>
#include <string>
#include <iostream>
using std::regex; using std::regex_match; using std::regex_search;
int main() {
std::cout << std::boolalpha;
regex muster {"ello"};
std::string text = "Hello world";
auto b1 = regex_match (text.cbegin(), text.cend(), muster); // passt nicht
std::cout << b1 << "\n"; // Ausgabe: false
auto b2 = regex_search(text.cbegin(), text.cend(), muster); // gefunden
std::cout << b2 << "\n"; // Ausgabe: true
}
Listing 28.12: Zugriff auf die Trefferdetails
Book listing lst-0907-book.cpp:
// https://godbolt.org/z/Ed8ca4Keq
#include <regex>
#include <string>
#include <iostream>
using std::regex; using std::regex_search; using std::cmatch;
int main() {
cmatch res; // für Detailergebnisse
std::string text = "<h2>Ergebnis und Teile davon</h2>";
regex muster{"<h(.)>([^<]+)"}; // Suchmuster mit Gruppen
regex_search(text.c_str(), res, muster); // Details nach res
std::cout << res[1] << ". " // ()-Gruppe 1: H-Ebene
<< res[2] << std::endl; // ()-Gruppe 2: H-Text
}
Godbolt Listing lst-0907-godb.cpp, https://godbolt.org/z/Ed8ca4Keq:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Ed8ca4Keq
#include <regex>
#include <string>
#include <iostream>
using std::regex; using std::regex_search; using std::cmatch;
int main() {
cmatch res; // für Detailergebnisse
std::string text = "<h2>Ergebnis und Teile davon</h2>";
regex muster{"<h(.)>([^<]+)"}; // Suchmuster mit Gruppen
regex_search(text.c_str(), res, muster); // Details nach res
std::cout << res[1] << ". " // ()-Gruppe 1: H-Ebene
<< res[2] << std::endl; // ()-Gruppe 2: H-Text
}
Listing 28.13: Treffer durch neuen Text ersetzen
Book listing lst-0908-book.cpp:
// https://godbolt.org/z/rErP43G89
#include <regex>
#include <string>
#include <iostream>
using std::string;
int main() {
string text = "Titel;Album;Interpret";
std::regex muster{";"};
string neu = std::regex_replace(text, muster, string{","});
std::cout << neu << "\n"; // Ausgabe: Titel,Album,Interpret
}
Godbolt Listing lst-0908-godb.cpp, https://godbolt.org/z/rErP43G89:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/rErP43G89
#include <regex>
#include <string>
#include <iostream>
using std::string;
int main() {
string text = "Titel;Album;Interpret";
std::regex muster{";"};
string neu = std::regex_replace(text, muster, string{","});
std::cout << neu << "\n"; // Ausgabe: Titel,Album,Interpret
}
Listing 28.14: Schwer zu wartender regulärer Ausdruck
Book listing lst-0911-book.cpp:
// https://godbolt.org/z/v91WoqjPj
#include <regex>
#include <string>
#include <iostream>
using std::regex; using std::regex_search; using std::cmatch;
const regex muster{R"(^score\s+(\d+)\s+for\s+(\d+)\s+nights?\s+at\s+(.*))"};
void extract(const std::string &text) {
cmatch res;
regex_search(text.c_str(), res, muster);
std::cout << res[1] << "," << res[2] << "," << res[3] << "\n";
}
int main() {
extract("score 400 for 2 nights at Minas Tirith Airport");
extract("score 84 for 1 night at Prancing Pony");
}
Godbolt Listing lst-0911-godb.cpp, https://godbolt.org/z/v91WoqjPj:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/v91WoqjPj
#include <regex>
#include <string>
#include <iostream>
using std::regex; using std::regex_search; using std::cmatch;
const regex muster{R"(^score\s+(\d+)\s+for\s+(\d+)\s+nights?\s+at\s+(.*))"};
void extract(const std::string &text) {
cmatch res;
regex_search(text.c_str(), res, muster);
std::cout << res[1] << "," << res[2] << "," << res[3] << "\n";
}
int main() {
extract("score 400 for 2 nights at Minas Tirith Airport");
extract("score 84 for 1 night at Prancing Pony");
}
Listing 28.15: Teile benennen und dann zusammenfügen
Book listing lst-0912-book.cpp:
// https://godbolt.org/z/TK6n4dG37
const string scoreKeyword = R"(^score\s+)";
const string numberOfPoints = R"((\d+))";
const string forKeyword = R"(\s+for\s+)";
const string numberOfNights = R"((\d+))";
const string nightsAtKeyword = R"(\s+nights?\s+at\s+)";
const string hotelName = R"((.*))";
const regex muster{ scoreKeyword + numberOfPoints +
forKeyword + numberOfNights + nightsAtKeyword + hotelName };
}
Godbolt Listing lst-0912-godb.cpp, https://godbolt.org/z/TK6n4dG37:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/TK6n4dG37
const string scoreKeyword = R"(^score\s+)";
const string numberOfPoints = R"((\d+))";
const string forKeyword = R"(\s+for\s+)";
const string numberOfNights = R"((\d+))";
const string nightsAtKeyword = R"(\s+nights?\s+at\s+)";
const string hotelName = R"((.*))";
const regex muster{ scoreKeyword + numberOfPoints +
forKeyword + numberOfNights + nightsAtKeyword + hotelName };
}
Listing 28.16: Innerhalb des Ausdrucks kommentieren
Book listing lst-0913-book.cpp:
// https://godbolt.org/z/MszTjE3dv
const regex muster{R"(^score)"
R"(\s+)"
R"((\d+))" // Punkte
R"(\s+)"
R"(for)"
R"(\s+)"
R"((\d+))" // Anzahl Nächte
R"(\s+)"
R"(night)"
R"(s?)" // optional: Plural
R"(\s+)"
R"(at)"
R"(\s+)"
R"((.*))" // Hotelname
R"()"};
Godbolt Listing lst-0913-godb.cpp, https://godbolt.org/z/MszTjE3dv:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/MszTjE3dv
const regex muster{R"(^score)"
R"(\s+)"
R"((\d+))" // Punkte
R"(\s+)"
R"(for)"
R"(\s+)"
R"((\d+))" // Anzahl Nächte
R"(\s+)"
R"(night)"
R"(s?)" // optional: Plural
R"(\s+)"
R"(at)"
R"(\s+)"
R"((.*))" // Hotelname
R"()"};
Listing 28.17: So erhalten Sie eine gleichverteilte Zufallszahl zwischen zwei Grenzen.
Book listing lst-0914-book.cpp:
// https://godbolt.org/z/6ecxTsYzj
#include <random>
#include <vector>
#include <iostream>
void wuerfel() {
std::default_random_engine engine{}; // Zufall normaler Qualität
std::vector<size_t> counts{0,0,0,0,0,0};
std::uniform_int_distribution<int> w6{0, 5}; // gleichverteilte Ganzzahlen
for(auto i=1200*1000; i>0; --i)
++counts[w6(engine)];
for(auto c : counts) std::cout<<" "<<c;
std::cout << '\n';
}
int main() {
wuerfel();
}
Godbolt Listing lst-0914-godb.cpp, https://godbolt.org/z/6ecxTsYzj:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/6ecxTsYzj
#include <random>
#include <vector>
#include <iostream>
void wuerfel() {
std::default_random_engine engine{}; // Zufall normaler Qualität
std::vector<size_t> counts{0,0,0,0,0,0};
std::uniform_int_distribution<int> w6{0, 5}; // gleichverteilte Ganzzahlen
for(auto i=1200*1000; i>0; --i)
++counts[w6(engine)];
for(auto c : counts) std::cout<<" "<<c;
std::cout << '\n';
}
int main() {
wuerfel();
}
Listing 28.18: Geschwindigkeiten der Zufallsgeneratoren
Book listing lst-0918-book.cpp:
// https://godbolt.org/z/W8WbbxY78
#include <random>
#include <chrono> // system_clock
#include <format>
#include <iostream>
using namespace std;
using namespace chrono;
const size_t LOOPS = 10*1000*1000;
template<typename ENGINE>
void messen(const string &title, ENGINE &engine) {
const auto start = steady_clock::now();
/* hart arbeiten */
unsigned long long checksum = 0;
size_t loops = LOOPS;
while(loops-- > 0)
checksum += engine();
const auto now = steady_clock::now();
nanoseconds dur_ns = now - start;
cout << std::format(" {}: {:5} ns/loop {:12} ns\n",
title, dur_ns.count() / LOOPS, dur_ns.count());
}
int main() {
{ default_random_engine e{}; messen(" default", e ); }
{ random_device e{}; messen(" device", e ); }
{ minstd_rand0 e{}; messen(" minstd_rand0", e ); }
{ minstd_rand e{}; messen(" minstd_rand ", e ); }
{ mt19937 e{}; messen(" mt19937 ", e ); }
{ mt19937_64 e{}; messen(" mt19937_64", e ); }
{ ranlux24_base e{}; messen("ranlux24_base", e ); }
{ ranlux48_base e{}; messen("ranlux48_base", e ); }
{ ranlux24 e{}; messen("ranlux24 ", e ); }
{ ranlux48 e{}; messen("ranlux48 ", e ); }
{ knuth_b e{}; messen(" knuth_b", e ); }
{
using wide_t = unsigned long long ;
independent_bits_engine<ranlux48, sizeof(wide_t)*8, wide_t> e{};
messen("indep<ranlux>", e );
}
{
using wide_t = unsigned long long;
independent_bits_engine<
default_random_engine,
sizeof(wide_t)*8, wide_t>
e {};
messen("indep<default>", e );
}
}
Godbolt Listing lst-0918-godb.cpp, https://godbolt.org/z/W8WbbxY78:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/W8WbbxY78
#include <random>
#include <chrono> // system_clock
#include <format>
#include <iostream>
using namespace std;
using namespace chrono;
const size_t LOOPS = 10*1000*1000;
template<typename ENGINE>
void messen(const string &title, ENGINE &engine) {
const auto start = steady_clock::now();
/* hart arbeiten */
unsigned long long checksum = 0;
size_t loops = LOOPS;
while(loops-- > 0)
checksum += engine();
const auto now = steady_clock::now();
nanoseconds dur_ns = now - start;
cout << std::format(" {}: {:5} ns/loop {:12} ns\n",
title, dur_ns.count() / LOOPS, dur_ns.count());
}
int main() {
{ default_random_engine e{}; messen(" default", e ); }
{ random_device e{}; messen(" device", e ); }
{ minstd_rand0 e{}; messen(" minstd_rand0", e ); }
{ minstd_rand e{}; messen(" minstd_rand ", e ); }
{ mt19937 e{}; messen(" mt19937 ", e ); }
{ mt19937_64 e{}; messen(" mt19937_64", e ); }
{ ranlux24_base e{}; messen("ranlux24_base", e ); }
{ ranlux48_base e{}; messen("ranlux48_base", e ); }
{ ranlux24 e{}; messen("ranlux24 ", e ); }
{ ranlux48 e{}; messen("ranlux48 ", e ); }
{ knuth_b e{}; messen(" knuth_b", e ); }
{
using wide_t = unsigned long long ;
independent_bits_engine<ranlux48, sizeof(wide_t)*8, wide_t> e{};
messen("indep<ranlux>", e );
}
{
using wide_t = unsigned long long;
independent_bits_engine<
default_random_engine,
sizeof(wide_t)*8, wide_t>
e {};
messen("indep<default>", e );
}
}
Listing 28.19: Eine Binomialverteilung
Book listing lst-0919-book.cpp:
// https://godbolt.org/z/hvM8K4oY6
#include <random>
#include <vector>
#include <iostream>
using namespace std;
int main() {
static const size_t size = 10;
default_random_engine e{}; // Zufallsgenerator
vector<size_t> counts(size+1);
binomial_distribution<int> muenzen{size}; // wirft 10 Münzen, 0- bis 10-mal Kopf
for(auto i=120*1000; i>0; --i)
++counts[muenzen(e)]; // Münzen werfen
for(auto c : counts) cout<<" "<<c;
cout << '\n';
// Beispielausgabe:
// 109 1159 5344 14043 24806 29505 24544 13973 5252 1150 115
}
Godbolt Listing lst-0919-godb.cpp, https://godbolt.org/z/hvM8K4oY6:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/hvM8K4oY6
#include <random>
#include <vector>
#include <iostream>
using namespace std;
int main() {
static const size_t size = 10;
default_random_engine e{}; // Zufallsgenerator
vector<size_t> counts(size+1);
binomial_distribution<int> muenzen{size}; // wirft 10 Münzen, 0- bis 10-mal Kopf
for(auto i=120*1000; i>0; --i)
++counts[muenzen(e)]; // Münzen werfen
for(auto c : counts) cout<<" "<<c;
cout << '\n';
// Beispielausgabe:
// 109 1159 5344 14043 24806 29505 24544 13973 5252 1150 115
}
Listing 28.20: Eine »double«-Zufallszahl
Book listing lst-0920-book.cpp:
// https://godbolt.org/z/94McsP7PG
#include <random>
#include <iostream>
int main() {
std::default_random_engine e{};
std::uniform_real_distribution<double> unif{3,7}; // im halboff. Intervall [3,7)
double u = unif(e); // Zufallszahl ermitteln
std::cout << u << '\n'; // Beispielausgabe: 3.52615
}
Godbolt Listing lst-0920-godb.cpp, https://godbolt.org/z/94McsP7PG:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/94McsP7PG
#include <random>
#include <iostream>
int main() {
std::default_random_engine e{};
std::uniform_real_distribution<double> unif{3,7}; // im halboff. Intervall [3,7)
double u = unif(e); // Zufallszahl ermitteln
std::cout << u << '\n'; // Beispielausgabe: 3.52615
}
Listing 28.21: Generierungsparameter für jede Zufallszahl einzeln ändern
Book listing lst-0921-book.cpp:
// https://godbolt.org/z/xz64qK3e5
#include <random>
#include <iostream>
int main() {
std::default_random_engine e{};
using Dstr = std::uniform_int_distribution<int>; // gleichverteilte int
Dstr karte{}; // Verteilung erzeugen
for(int n=32; n>=1; --n)
std::cout <<" "<< karte(e, Dstr::param_type{1,n} ); // Parameter erst hier
std::cout << '\n';
// Ausgabe zum Beispiel:
// 1 5 23 14 15 6 2 17 17 22 9 11 17 1 1 10 11 1 6 1 6 8 6 9 7 4 1 4 2 3 2 1
}
Godbolt Listing lst-0921-godb.cpp, https://godbolt.org/z/xz64qK3e5:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/xz64qK3e5
#include <random>
#include <iostream>
int main() {
std::default_random_engine e{};
using Dstr = std::uniform_int_distribution<int>; // gleichverteilte int
Dstr karte{}; // Verteilung erzeugen
for(int n=32; n>=1; --n)
std::cout <<" "<< karte(e, Dstr::param_type{1,n} ); // Parameter erst hier
std::cout << '\n';
// Ausgabe zum Beispiel:
// 1 5 23 14 15 6 2 17 17 22 9 11 17 1 1 10 11 1 6 1 6 8 6 9 7 4 1 4 2 3 2 1
}
GodboltId:173nr4xxd
Book listing lst-0926-book.cpp:
// https://godbolt.org/z/173nr4xxd
sleep(10min);
sleep(std::chrono::minutes{10});
sleep(std::chrono::duration<unsigned long,std::ratio<60>>{10});
Godbolt Listing lst-0926-godb.cpp, https://godbolt.org/z/173nr4xxd:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/173nr4xxd
sleep(10min);
sleep(std::chrono::minutes{10});
sleep(std::chrono::duration<unsigned long,std::ratio<60>>{10});
GodboltId:5snr1hq9b
Book listing lst-0927-book.cpp:
// https://godbolt.org/z/5snr1hq9b
#include <chrono>
void sleep(std::chrono::seconds s) { // nimmt Sekunden als Dauer
/* ... */
}
/* ... */
int main() {
using namespace std::chrono; // Literale verfügbar machen
sleep(10min); // 10 Minuten warten, also 600 Sekunden
sleep(10ms); // (ERR) 10 Millisekunden? Mit Sekunden nicht abzubilden.
}
Godbolt Listing lst-0927-godb.cpp, https://godbolt.org/z/5snr1hq9b:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/5snr1hq9b
#include <chrono>
void sleep(std::chrono::seconds s) { // nimmt Sekunden als Dauer
/* ... */
}
/* ... */
int main() {
using namespace std::chrono; // Literale verfügbar machen
sleep(10min); // 10 Minuten warten, also 600 Sekunden
sleep(10ms); // (ERR) 10 Millisekunden? Mit Sekunden nicht abzubilden.
}
GodboltId:h8vsjxsME
Book listing lst-0929-book.cpp:
// https://godbolt.org/z/h8vsjxsME
#include <cinttypes> // int64_t
namespace std { namespace chrono {
class seconds {
int64_t sec_;
public:
seconds() = default;
// … etc …
};
} }
Godbolt Listing lst-0929-godb.cpp, https://godbolt.org/z/h8vsjxsME:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/h8vsjxsME
#include <cinttypes> // int64_t
namespace std { namespace chrono {
class seconds {
int64_t sec_;
public:
seconds() = default;
// … etc …
};
} }
Listing 28.22: Mit »seconds« können Sie rechnen.
Book listing lst-0934-book.cpp:
// https://godbolt.org/z/hPPrPT69h
#include <chrono>
#include <iostream>
void sleep(std::chrono::seconds dur) {
std::cout << dur.count() << "s\n";
/* ... */
}
int main() {
using namespace std::chrono;
sleep(3); // (ERR) Fehler: keine implizite Konvertierung von int
sleep(seconds{4}); // okay
sleep(5s); // okay
seconds x{6};
sleep(x); // okay
auto y = 10s;
y += 20s; // Inkrementieren mit Sekunden
sleep(y); // nun also 30s
y = y - 6s; // Subtraktion von Sekunden
sleep(y); // und nun nur noch 24s
y /= 2; // Division durch einen Skalar
sleep(y); // 12s
sleep(y + 7); // (ERR) Fehler: seconds+int geht nicht
}
Godbolt Listing lst-0934-godb.cpp, https://godbolt.org/z/hPPrPT69h:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/hPPrPT69h
#include <chrono>
#include <iostream>
void sleep(std::chrono::seconds dur) {
std::cout << dur.count() << "s\n";
/* ... */
}
int main() {
using namespace std::chrono;
sleep(3); // (ERR) Fehler: keine implizite Konvertierung von int
sleep(seconds{4}); // okay
sleep(5s); // okay
seconds x{6};
sleep(x); // okay
auto y = 10s;
y += 20s; // Inkrementieren mit Sekunden
sleep(y); // nun also 30s
y = y - 6s; // Subtraktion von Sekunden
sleep(y); // und nun nur noch 24s
y /= 2; // Division durch einen Skalar
sleep(y); // 12s
sleep(y + 7); // (ERR) Fehler: seconds+int geht nicht
}
Listing 28.23: Sie können »seconds« vergleichen.
Book listing lst-0935-book.cpp:
// https://godbolt.org/z/8c1r5xrs5
#include <chrono>
#include <iostream>
using std::chrono::operator""s; // nur Literalsuffix verfügbar machen
constexpr auto limit = 10s;
void action(std::chrono::seconds dur) {
if(dur <= limit) { // vergleichen
std::cout << dur.count() << "s\n";
} else {
std::cout << "zu lang!\n";
}
}
int main() {
action(4s); // Ausgabe: 4s
action(20s); // Ausgabe: zu lang!
}
Godbolt Listing lst-0935-godb.cpp, https://godbolt.org/z/8c1r5xrs5:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/8c1r5xrs5
#include <chrono>
#include <iostream>
using std::chrono::operator""s; // nur Literalsuffix verfügbar machen
constexpr auto limit = 10s;
void action(std::chrono::seconds dur) {
if(dur <= limit) { // vergleichen
std::cout << dur.count() << "s\n";
} else {
std::cout << "zu lang!\n";
}
}
int main() {
action(4s); // Ausgabe: 4s
action(20s); // Ausgabe: zu lang!
}
Listing 28.24: Automatische Umrechnung zwischen Zeiteinheiten
Book listing lst-0936-book.cpp:
// https://godbolt.org/z/qrs63vdz1
#include <chrono>
#include <iostream>
int main() {
using namespace std::chrono; // Suffixe erlauben
seconds mySecs = 121s; // seconds{121}
std::cout << mySecs.count() << "s\n"; // Ausgabe: 121s
milliseconds myMillis = mySecs; // automatisch umgewandelt
std::cout << myMillis.count() << "ms\n"; // Ausgabe: 121000ms
nanoseconds myNanos = mySecs;
std::cout << myNanos.count() << "ns\n"; // Ausgabe: 121000000000ns
minutes myMinutesErr = mySecs; // (ERR) Fehler: Konvertierung mit Verlust
minutes myMinutes = duration_cast<minutes>(mySecs); // explizit geht's
std::cout<<myMinutes.count()<<"min\n"; // Ausgabe: 2min
}
Godbolt Listing lst-0936-godb.cpp, https://godbolt.org/z/qrs63vdz1:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/qrs63vdz1
#include <chrono>
#include <iostream>
int main() {
using namespace std::chrono; // Suffixe erlauben
seconds mySecs = 121s; // seconds{121}
std::cout << mySecs.count() << "s\n"; // Ausgabe: 121s
milliseconds myMillis = mySecs; // automatisch umgewandelt
std::cout << myMillis.count() << "ms\n"; // Ausgabe: 121000ms
nanoseconds myNanos = mySecs;
std::cout << myNanos.count() << "ns\n"; // Ausgabe: 121000000000ns
minutes myMinutesErr = mySecs; // (ERR) Fehler: Konvertierung mit Verlust
minutes myMinutes = duration_cast<minutes>(mySecs); // explizit geht's
std::cout<<myMinutes.count()<<"min\n"; // Ausgabe: 2min
}
Listing 28.26: Sie können Einheiten mischen.
Book listing lst-0937-book.cpp:
// https://godbolt.org/z/vTx4cdqzq
#include <chrono>
#include <iostream>
void showDuration(std::chrono::milliseconds dur) {
std::cout << dur.count() << "ms\n";
}
int main() {
using namespace std::chrono;
auto x = 2s;
auto y = 3ms;
showDuration(x + y); // Ausgabe: 2003ms
showDuration(x - y); // Ausgabe: 1997ms
}
Godbolt Listing lst-0937-godb.cpp, https://godbolt.org/z/vTx4cdqzq:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/vTx4cdqzq
#include <chrono>
#include <iostream>
void showDuration(std::chrono::milliseconds dur) {
std::cout << dur.count() << "ms\n";
}
int main() {
using namespace std::chrono;
auto x = 2s;
auto y = 3ms;
showDuration(x + y); // Ausgabe: 2003ms
showDuration(x - y); // Ausgabe: 1997ms
}
Listing 28.27: Erstellen Sie neue Zeiteinheiten oder sparsamere Repräsentationen.
Book listing lst-0938-book.cpp:
// https://godbolt.org/z/5Wd1rKrMe
#include <chrono>
#include <iostream>
using namespace std::chrono; using std::cout;
using seconds32 = duration<int32_t>; // andere Repräsentation
using zehntag = duration<int,std::ratio<86400*10>>; // andere Zeiteinheit
using fseconds = duration<double>; // Fließkommarepräsentation
int main() {
seconds32 s{5};
cout << milliseconds(s).count() << "ms\n";
zehntag z{1};
hours h = z; // Umwandlung kostenlos
cout << "1 Zehntag hat "<<h.count()<<" Stunden\n"; // …240…
fseconds fs{23.75};
cout << fs.count() << "s\n"; // Fließkommaausgabe
auto printDur = [](fseconds f) { cout << f.count() << "s\n"; }; // Funktion
printDur(45ms + 63us); // Umwandlung in fseconds
// Ausgabe: 0.045063s
}
Godbolt Listing lst-0938-godb.cpp, https://godbolt.org/z/5Wd1rKrMe:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/5Wd1rKrMe
#include <chrono>
#include <iostream>
using namespace std::chrono; using std::cout;
using seconds32 = duration<int32_t>; // andere Repräsentation
using zehntag = duration<int,std::ratio<86400*10>>; // andere Zeiteinheit
using fseconds = duration<double>; // Fließkommarepräsentation
int main() {
seconds32 s{5};
cout << milliseconds(s).count() << "ms\n";
zehntag z{1};
hours h = z; // Umwandlung kostenlos
cout << "1 Zehntag hat "<<h.count()<<" Stunden\n"; // …240…
fseconds fs{23.75};
cout << fs.count() << "s\n"; // Fließkommaausgabe
auto printDur = [](fseconds f) { cout << f.count() << "s\n"; }; // Funktion
printDur(45ms + 63us); // Umwandlung in fseconds
// Ausgabe: 0.045063s
}
GodboltId:Gvz4crW75
Book listing lst-0939-book.cpp:
// https://godbolt.org/z/Gvz4crW75
#include <chrono>
#include <iostream>
using namespace std::chrono;
int main() {
year y{2021};
std::cout << y << "\n";
month m{October};
auto result = m + months{3}; // 'months', nicht 'month': 3 Monate später
std::cout << result << "\n"; // übergelaufen zu Januar
weekday wd{Thursday};
auto result = wd + days{4}; // 'days', nicht 'day': 4 Tage später
std::cout << result << "\n"; // übergelaufen zu Montag
weekday sun1{0}; // 0 ist Sonntag
weekday sun2{7}; // 7 ist auch Sonntag
std::cout << sun1 << "\t" << sun2 << "\n";
weekday_indexed wdi{wd, 4}; // unbestimmter 4. Donnerstag
std::cout << wdi << "\n"; // Ausgabe: Thu[4] — so gibt chrono
// unbestimmte Werte aus
}
Godbolt Listing lst-0939-godb.cpp, https://godbolt.org/z/Gvz4crW75:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Gvz4crW75
#include <chrono>
#include <iostream>
using namespace std::chrono;
int main() {
year y{2021};
std::cout << y << "\n";
month m{October};
auto result = m + months{3}; // 'months', nicht 'month': 3 Monate später
std::cout << result << "\n"; // übergelaufen zu Januar
weekday wd{Thursday};
auto result = wd + days{4}; // 'days', nicht 'day': 4 Tage später
std::cout << result << "\n"; // übergelaufen zu Montag
weekday sun1{0}; // 0 ist Sonntag
weekday sun2{7}; // 7 ist auch Sonntag
std::cout << sun1 << "\t" << sun2 << "\n";
weekday_indexed wdi{wd, 4}; // unbestimmter 4. Donnerstag
std::cout << wdi << "\n"; // Ausgabe: Thu[4] — so gibt chrono
// unbestimmte Werte aus
}
GodboltId:oaKbd9bd4
Book listing lst-0940-book.cpp:
// https://godbolt.org/z/oaKbd9bd4
#include <chrono>
#include <iostream>
using namespace std::chrono;
int main() {
year this_year{2021};
year last_year{2020};
year_month_day ymd{this_year, October, day{28}};
std::cout << ymd << "\n";
month_weekday mwd{November, Thursday[4]}; // in einem unbestimmten Jahr
std::cout << mwd << "\n"; // Ausgabe: Nov/Thu[4]
month_day_last mdlast{February}; // letzter Tag eines unbestimmten Februars
year_month_day_last leap{last_year, mdlast}; // Jahr hinzufügen
year_month_day_last noleap{this_year, mdlast}; // Jahr hinzufügen
std::cout << leap << "\t" << leap.day() << "\n"; // Ausgabe: 2020-02-29 29
std::cout << noleap << "\t" << noleap.day() << "\n"; // Ausgabe: 2021-02-28 28
}
Godbolt Listing lst-0940-godb.cpp, https://godbolt.org/z/oaKbd9bd4:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/oaKbd9bd4
#include <chrono>
#include <iostream>
using namespace std::chrono;
int main() {
year this_year{2021};
year last_year{2020};
year_month_day ymd{this_year, October, day{28}};
std::cout << ymd << "\n";
month_weekday mwd{November, Thursday[4]}; // in einem unbestimmten Jahr
std::cout << mwd << "\n"; // Ausgabe: Nov/Thu[4]
month_day_last mdlast{February}; // letzter Tag eines unbestimmten Februars
year_month_day_last leap{last_year, mdlast}; // Jahr hinzufügen
year_month_day_last noleap{this_year, mdlast}; // Jahr hinzufügen
std::cout << leap << "\t" << leap.day() << "\n"; // Ausgabe: 2020-02-29 29
std::cout << noleap << "\t" << noleap.day() << "\n"; // Ausgabe: 2021-02-28 28
}
GodboltId:4s69W7qd3
Book listing lst-0942-book.cpp:
// https://godbolt.org/z/4s69W7qd3
auto a_date = 2024y/11/14d;
auto b_date = 2024y/11/14;
auto c_date = 14d/11/2024;
auto d_date = November/14/2024;
Godbolt Listing lst-0942-godb.cpp, https://godbolt.org/z/4s69W7qd3:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/4s69W7qd3
auto a_date = 2024y/11/14d;
auto b_date = 2024y/11/14;
auto c_date = 14d/11/2024;
auto d_date = November/14/2024;
Listing 28.28: Ausgabe von Datum und Zeit mit format
Book listing lst-0944-book.cpp:
// https://godbolt.org/z/Md38b9zvf
#include <chrono>
#include <iostream>
#include <format>
using namespace std::chrono;
int main() {
auto ymd = last/February/2024; // letzter Tag im Februar 2024: 29.2.2024
std::cout << ymd << "\n"; // die Ausgabe mit << ist einfach
std::cout << std::format("{:%Y-%m-%d}\n", ymd); // format ist flexibler
std::cout << std::format("{:%e. %B %y}\n", ymd); // viel flexibler!
}
Godbolt Listing lst-0944-godb.cpp, https://godbolt.org/z/Md38b9zvf:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Md38b9zvf
#include <chrono>
#include <iostream>
#include <format>
using namespace std::chrono;
int main() {
auto ymd = last/February/2024; // letzter Tag im Februar 2024: 29.2.2024
std::cout << ymd << "\n"; // die Ausgabe mit << ist einfach
std::cout << std::format("{:%Y-%m-%d}\n", ymd); // format ist flexibler
std::cout << std::format("{:%e. %B %y}\n", ymd); // viel flexibler!
}
Listing 28.29: Immer der zweite Dienstag eines Monats
Book listing lst-0945-book.cpp:
// https://godbolt.org/z/19vf9jfTM
#include <chrono>
#include <iostream>
using namespace std::chrono;
int main() {
for (int mo = 1; mo <= 12; ++mo) {
year_month_weekday patch_tues{mo/Tuesday[2]/2024y};
year_month_day ymd{sys_days{patch_tues}};
std::cout << ymd.month() << " " << ymd.day() << "\n";
}
}
Godbolt Listing lst-0945-godb.cpp, https://godbolt.org/z/19vf9jfTM:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/19vf9jfTM
#include <chrono>
#include <iostream>
using namespace std::chrono;
int main() {
for (int mo = 1; mo <= 12; ++mo) {
year_month_weekday patch_tues{mo/Tuesday[2]/2024y};
year_month_day ymd{sys_days{patch_tues}};
std::cout << ymd.month() << " " << ymd.day() << "\n";
}
}
Listing 28.30: Umwandlung in eine zeitzonenbehaftete Zeit und die Ausnahmen
Book listing lst-0947-book.cpp:
// https://godbolt.org/z/hP7nhEW69
#include <chrono>
#include <iostream>
using namespace std::chrono;
int main() {
auto fruehl = local_days{31d/March/2024} + 2h + 1min;
try {
auto zt = zoned_time{"Europe/Berlin", fruehl};
} catch (const nonexistent_local_time& e) {
std::cout << e.what() << '\n'; // Ausnahme geworfen: existiert nicht
}
auto herbst = local_days{27d/October/2024} + 2h + 1min;
try {
auto zt = zoned_time{"Europe/Berlin", herbst};
} catch (const ambiguous_local_time& e) {
std::cout << e.what() << '\n'; // Ausnahme geworfen: existiert doppelt
}
std::cout << zoned_time{"Europe/Berlin", herbst, choose::earliest} << '\n';
// Ausgabe: 2024-10-27 02:01:00 CEST
std::cout << zoned_time{"Europe/Berlin", herbst, choose::latest} << '\n';
// Ausgabe: 2024-10-27 02:01:00 CET
}
Godbolt Listing lst-0947-godb.cpp, https://godbolt.org/z/hP7nhEW69:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/hP7nhEW69
#include <chrono>
#include <iostream>
using namespace std::chrono;
int main() {
auto fruehl = local_days{31d/March/2024} + 2h + 1min;
try {
auto zt = zoned_time{"Europe/Berlin", fruehl};
} catch (const nonexistent_local_time& e) {
std::cout << e.what() << '\n'; // Ausnahme geworfen: existiert nicht
}
auto herbst = local_days{27d/October/2024} + 2h + 1min;
try {
auto zt = zoned_time{"Europe/Berlin", herbst};
} catch (const ambiguous_local_time& e) {
std::cout << e.what() << '\n'; // Ausnahme geworfen: existiert doppelt
}
std::cout << zoned_time{"Europe/Berlin", herbst, choose::earliest} << '\n';
// Ausgabe: 2024-10-27 02:01:00 CEST
std::cout << zoned_time{"Europe/Berlin", herbst, choose::latest} << '\n';
// Ausgabe: 2024-10-27 02:01:00 CET
}
Listing 28.31: Die Zeitzonendatenbank
Book listing lst-0948-book.cpp:
// https://godbolt.org/z/YTKK3vT7s
#include <chrono>
#include <iostream>
#include <ranges> // views::transform, views::filter
#include <algorithm> // ranges::for_each
using namespace std; namespace c = std::chrono;
namespace v = std::views; namespace r = std::ranges;
int main() {
auto show_name = [](const string_view name) { cout << name << ' '; };
const auto& db = c::get_tzdb();
auto names = db.zones
| v::transform([](const c::time_zone& z) {return z.name();})
| v::filter([](const string_view name) {
return name.starts_with("Europe/Be");});
r::for_each(names, show_name);
cout << " <- Europe/Be*\n"; // Ausgabe: Europe/Belgrade Europe/Berlin
r::for_each(
db.links
| v::filter([](const c::time_zone_link& l){
return l.target()=="Europe/Berlin";})
| v::transform([](const c::time_zone_link& l)->string_view {
return l.name();})
, show_name);
cout << " <- Links nach Europe/Berlin\n"; // Ausgabe: Arctic/Longyearbyen …
}
Godbolt Listing lst-0948-godb.cpp, https://godbolt.org/z/YTKK3vT7s:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/YTKK3vT7s
#include <chrono>
#include <iostream>
#include <ranges> // views::transform, views::filter
#include <algorithm> // ranges::for_each
using namespace std; namespace c = std::chrono;
namespace v = std::views; namespace r = std::ranges;
int main() {
auto show_name = [](const string_view name) { cout << name << ' '; };
const auto& db = c::get_tzdb();
auto names = db.zones
| v::transform([](const c::time_zone& z) {return z.name();})
| v::filter([](const string_view name) {
return name.starts_with("Europe/Be");});
r::for_each(names, show_name);
cout << " <- Europe/Be*\n"; // Ausgabe: Europe/Belgrade Europe/Berlin
r::for_each(
db.links
| v::filter([](const c::time_zone_link& l){
return l.target()=="Europe/Berlin";})
| v::transform([](const c::time_zone_link& l)->string_view {
return l.name();})
, show_name);
cout << " <- Links nach Europe/Berlin\n"; // Ausgabe: Arctic/Longyearbyen …
}
GodboltId:YsjvxTKGj
Book listing lst-0949-book.cpp:
// https://godbolt.org/z/YsjvxTKGj
#include <iostream>
#include <ratio>
using std::cout; using std::endl;
int main() {
using einDrittel = std::ratio<1,3>;
using zweiViertel = std::ratio<2,4>;
cout << einDrittel::num << "/" << einDrittel::den << endl; // Ausgabe: 1/3
cout << zweiViertel::num << "/" << zweiViertel::den << endl; // Ausgabe: 1/2
using sum = std::ratio_add<einDrittel,zweiViertel>; // addieren
cout << sum::num << "/" << sum::den; // Ausgabe: 5/6
}
Godbolt Listing lst-0949-godb.cpp, https://godbolt.org/z/YsjvxTKGj:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/YsjvxTKGj
#include <iostream>
#include <ratio>
using std::cout; using std::endl;
int main() {
using einDrittel = std::ratio<1,3>;
using zweiViertel = std::ratio<2,4>;
cout << einDrittel::num << "/" << einDrittel::den << endl; // Ausgabe: 1/3
cout << zweiViertel::num << "/" << zweiViertel::den << endl; // Ausgabe: 1/2
using sum = std::ratio_add<einDrittel,zweiViertel>; // addieren
cout << sum::num << "/" << sum::den; // Ausgabe: 5/6
}
GodboltId:q1znGWb85
Book listing lst-0954-book.cpp:
// https://godbolt.org/z/q1znGWb85
#include <iostream>
#include <chrono>
int main() {
using namespace std::chrono;
time_point<system_clock, seconds> t1{10000s};
time_point<system_clock, seconds> t2{50000s};
auto dur = t2 - t1;
std::cout << duration_cast<hours>(dur).count() << "h"; // Ausgabe: 11h
}
Godbolt Listing lst-0954-godb.cpp, https://godbolt.org/z/q1znGWb85:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/q1znGWb85
#include <iostream>
#include <chrono>
int main() {
using namespace std::chrono;
time_point<system_clock, seconds> t1{10000s};
time_point<system_clock, seconds> t2{50000s};
auto dur = t2 - t1;
std::cout << duration_cast<hours>(dur).count() << "h"; // Ausgabe: 11h
}
Listing 28.32: Einfache Zeitmessung eines Funktionsaufrufs
Book listing lst-0958-book.cpp:
// https://godbolt.org/z/8hxd9bPb4
#include <iostream>
#include <chrono>
long fib(long n) { return n<2L ? 1L : fib(n-1L)+fib(n-2L); }
int main() {
using namespace std::chrono;
auto t0 = steady_clock::now(); // Auf die Plätze, fertig …
auto res = fib(17); // … los!
auto t1 = steady_clock::now(); // Stopp!
std::cout << "Ergebnis: " << res << "\n"; // Ausgabe: Ergebnis: 2584
std::cout << "Zeit: " << nanoseconds{t1-t0}.count() << "ns\n";
// Ausgabe: Zeit: 50727ns (z. B.)
}
Godbolt Listing lst-0958-godb.cpp, https://godbolt.org/z/8hxd9bPb4:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/8hxd9bPb4
#include <iostream>
#include <chrono>
long fib(long n) { return n<2L ? 1L : fib(n-1L)+fib(n-2L); }
int main() {
using namespace std::chrono;
auto t0 = steady_clock::now(); // Auf die Plätze, fertig …
auto res = fib(17); // … los!
auto t1 = steady_clock::now(); // Stopp!
std::cout << "Ergebnis: " << res << "\n"; // Ausgabe: Ergebnis: 2584
std::cout << "Zeit: " << nanoseconds{t1-t0}.count() << "ns\n";
// Ausgabe: Zeit: 50727ns (z. B.)
}
GodboltId:rz38hc1cx
Book listing lst-0959-book.cpp:
// https://godbolt.org/z/rz38hc1cx
auto res = fib(45);
// …
std::cout << "Zeit: " << duration_cast<seconds>(t1-t0).count() << "s\n";
// Ausgabe: Zeit: 7s (z. B.)
std::cout << "Zeit: " << duration<double>{t1-t0}.count() << "s\n";
// Ausgabe: Zeit: 7.35303s (z. B.)
}
Godbolt Listing lst-0959-godb.cpp, https://godbolt.org/z/rz38hc1cx:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/rz38hc1cx
auto res = fib(45);
// …
std::cout << "Zeit: " << duration_cast<seconds>(t1-t0).count() << "s\n";
// Ausgabe: Zeit: 7s (z. B.)
std::cout << "Zeit: " << duration<double>{t1-t0}.count() << "s\n";
// Ausgabe: Zeit: 7.35303s (z. B.)
}
GodboltId:1xbhhTdEv
Book listing lst-0960-book.cpp:
// https://godbolt.org/z/1xbhhTdEv
#include <iostream>
#include <chrono>
int main() {
using namespace std::chrono;
auto tp = time_point_cast<seconds>(system_clock::now());
auto d = tp.time_since_epoch();
std::cout << d.count() << "s\n";
std::cout << duration<double,std::ratio<86400>>{d}.count() << "days\n";
}
Godbolt Listing lst-0960-godb.cpp, https://godbolt.org/z/1xbhhTdEv:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/1xbhhTdEv
#include <iostream>
#include <chrono>
int main() {
using namespace std::chrono;
auto tp = time_point_cast<seconds>(system_clock::now());
auto d = tp.time_since_epoch();
std::cout << d.count() << "s\n";
std::cout << duration<double,std::ratio<86400>>{d}.count() << "days\n";
}
GodboltId:o359TThMj
Book listing lst-0961-book.cpp:
// https://godbolt.org/z/o359TThMj
#include <iostream>
#include <string>
#include <chrono>
#include <complex>
using std::cout;
int main() {
{ using namespace std;
cout << "string"s << "\n"; // string
cout << (1.2+3.4i) << "\n"; // complex
}
{ using namespace std::chrono;
cout << (35ms).count() << "ms\n"; // chrono
}
{ using namespace std::literals;
cout << (41s).count() << "ms\n"; // chrono seconds
cout << "text"s << "\n"; // string
}
{ using namespace std::chrono;
cout << (4h).count() << "h\n"; // chrono hours
}
{ using namespace std::literals::chrono_literals;
cout << (16min).count() << "min\n"; // chrono minutes
}
{ using std::literals::string_literals::operator""s;
cout << "buchstaben"s << "\n"; // string
}
}
Godbolt Listing lst-0961-godb.cpp, https://godbolt.org/z/o359TThMj:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/o359TThMj
#include <iostream>
#include <string>
#include <chrono>
#include <complex>
using std::cout;
int main() {
{ using namespace std;
cout << "string"s << "\n"; // string
cout << (1.2+3.4i) << "\n"; // complex
}
{ using namespace std::chrono;
cout << (35ms).count() << "ms\n"; // chrono
}
{ using namespace std::literals;
cout << (41s).count() << "ms\n"; // chrono seconds
cout << "text"s << "\n"; // string
}
{ using namespace std::chrono;
cout << (4h).count() << "h\n"; // chrono hours
}
{ using namespace std::literals::chrono_literals;
cout << (16min).count() << "min\n"; // chrono minutes
}
{ using std::literals::string_literals::operator""s;
cout << "buchstaben"s << "\n"; // string
}
}
Listing 28.34: Sehr einfaches Beispiel dafür, wie man den Erfolg einer Operation prüfen kann
Book listing lst-0962-book.cpp:
// https://godbolt.org/z/1xnY8vd8Y
#include <system_error> // error_code
#include <string>
void create_dir(const std::string& pathname, std::error_code& ec);
void run() {
std::error_code ec;
create_dir("/some/path", ec);
if(!ec) { // Erfolg …
} else { // Misserfolg …
}
}
Godbolt Listing lst-0962-godb.cpp, https://godbolt.org/z/1xnY8vd8Y:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/1xnY8vd8Y
#include <system_error> // error_code
#include <string>
void create_dir(const std::string& pathname, std::error_code& ec);
void run() {
std::error_code ec;
create_dir("/some/path", ec);
if(!ec) { // Erfolg …
} else { // Misserfolg …
}
}
Listing 28.35: Vergleich von »error_code« mit »error_condition«
Book listing lst-0963-book.cpp:
// https://godbolt.org/z/TPWc5nexq
#include <system_error> // error_code, errc
#include <string>
void create_dir(const std::string& pathname, std::error_code& ec);
void run() {
std::error_code ec;
create_dir("/some/path", ec);
if(ec == std::errc::file_exists) { // speziell …
} else if(!ec) { // Erfolg …
} else { // Misserfolg …
}
}
Godbolt Listing lst-0963-godb.cpp, https://godbolt.org/z/TPWc5nexq:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/TPWc5nexq
#include <system_error> // error_code, errc
#include <string>
void create_dir(const std::string& pathname, std::error_code& ec);
void run() {
std::error_code ec;
create_dir("/some/path", ec);
if(ec == std::errc::file_exists) { // speziell …
} else if(!ec) { // Erfolg …
} else { // Misserfolg …
}
}
Listing 28.36: Überladungen von »operator==()« (abgekürzt)
Book listing lst-0964-book.cpp:
bool operator==
(const error_code& lhs, const error_code& rhs) noexcept;
…(const error_code& lhs, const error_condition& rhs) noexcept;
…(const error_condition& lhs, const error_code& rhs) noexcept;
…(const error_condition& lhs, const error_condition& rhs) noexcept;
Listing 28.37: Definition von »enum class errc«
Book listing lst-0965-book.cpp:
enum class errc {
address_family_not_supported,
address_in_use,
// ...
value_too_large,
wrong_protocol_type,
};
Listing 28.38: Spezialisierung von »is_error_condition_enum« für »errc«
Book listing lst-0966-book.cpp:
template <>
struct is_error_condition_enum<errc> : true_type {};
Listing 28.39: Unter den Überladungen von make_error_condition ist auch eine mit »errc«.
Book listing lst-0967-book.cpp:
error_condition make_error_condition(errc c) noexcept {
return error_condition(
static_cast<int>(e),
generic_category());
}
error_condition make_error_condition(io_errc c) noexcept /*...*/
error_condition make_error_condition(future_errc c) noexcept /*...*/
Listing 28.40: Erzeugung systemspezifischer Fehlercodes in einem portablen Programm
Book listing lst-0968-book.cpp:
// https://godbolt.org/z/n4v78WWod
#include <system_error>
#include <string>
void create_dir(const std::string& pathname, std::error_code& ec) {
#if defined(_WIN32)
// Windows-Implementierung, mit Windows-Fehlercodes
#elif defined(linux)
// Linux-Implementierung, mit Linux-Fehlercodes
#else
// allgemeingültiger 'generischer' Fall
ec = std::make_error_code(std::errc::not_supported);
#endif
}
Godbolt Listing lst-0968-godb.cpp, https://godbolt.org/z/n4v78WWod:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/n4v78WWod
#include <system_error>
#include <string>
void create_dir(const std::string& pathname, std::error_code& ec) {
#if defined(_WIN32)
// Windows-Implementierung, mit Windows-Fehlercodes
#elif defined(linux)
// Linux-Implementierung, mit Linux-Fehlercodes
#else
// allgemeingültiger 'generischer' Fall
ec = std::make_error_code(std::errc::not_supported);
#endif
}
GodboltId:vxTxT4ajW
Book listing lst-0969-book.cpp:
// https://godbolt.org/z/vxTxT4ajW
#include <system_error>
#include <iostream>
using std::error_code; using std::system_category;
namespace mylib {
// eigene Errorcodes
enum class errc { LOAD_ERR = 1, UNLOAD_ERR = 2, OTHER_ERR = 3 };
error_code make_error_code(errc ec) {
switch(ec) {
case errc::LOAD_ERR: return error_code((int)ec, system_category());
case errc::UNLOAD_ERR: return error_code((int)ec, system_category());
case errc::OTHER_ERR: return error_code((int)ec, system_category());
}
}
error_code run(int arg) {
if(arg == 667) {
return make_error_code(errc::OTHER_ERR);
}
return error_code{}; // alles gut.
}
}
int main() {
std::error_code ec = mylib::run(667);
if(!ec) {
std::cout << "Klasse, klappt!\n";
} else if (ec == mylib::make_error_code(mylib::errc::OTHER_ERR)) {
std::cout << "Anderer Fehler\n";
} else {
std::cout << "Nix los hier\n" << ec;
}
}
Godbolt Listing lst-0969-godb.cpp, https://godbolt.org/z/vxTxT4ajW:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/vxTxT4ajW
#include <system_error>
#include <iostream>
using std::error_code; using std::system_category;
namespace mylib {
// eigene Errorcodes
enum class errc { LOAD_ERR = 1, UNLOAD_ERR = 2, OTHER_ERR = 3 };
error_code make_error_code(errc ec) {
switch(ec) {
case errc::LOAD_ERR: return error_code((int)ec, system_category());
case errc::UNLOAD_ERR: return error_code((int)ec, system_category());
case errc::OTHER_ERR: return error_code((int)ec, system_category());
}
}
error_code run(int arg) {
if(arg == 667) {
return make_error_code(errc::OTHER_ERR);
}
return error_code{}; // alles gut.
}
}
int main() {
std::error_code ec = mylib::run(667);
if(!ec) {
std::cout << "Klasse, klappt!\n";
} else if (ec == mylib::make_error_code(mylib::errc::OTHER_ERR)) {
std::cout << "Anderer Fehler\n";
} else {
std::cout << "Nix los hier\n" << ec;
}
}
GodboltId:a8zP84j1x
Book listing lst-0971-book.cpp:
// https://godbolt.org/z/a8zP84j1x
#include <thread>
#include <iostream>
#include <system_error>
int main() {
try {
std::thread().detach(); // das wird fehlschlagen
} catch(std::system_error& e) {
std::cout
<< "system_error mit Code:" << e.code()
<< " Meldung:" << e.what()
<< '\n';
}
}
Godbolt Listing lst-0971-godb.cpp, https://godbolt.org/z/a8zP84j1x:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/a8zP84j1x
#include <thread>
#include <iostream>
#include <system_error>
int main() {
try {
std::thread().detach(); // das wird fehlschlagen
} catch(std::system_error& e) {
std::cout
<< "system_error mit Code:" << e.code()
<< " Meldung:" << e.what()
<< '\n';
}
}
GodboltId:cjh93oPcr
Book listing lst-0972-book.cpp:
// https://godbolt.org/z/cjh93oPcr
#include <iostream>
#include <system_error> // std::make_error_condition, std::ios_errc
int main () {
// umschalten auf Exceptions:
std::cin.exceptions (std::ios::failbit|std::ios::badbit);
try {
std::cin.rdbuf(nullptr); // löst eine Exception aus
} catch (std::ios::failure& e) { // abgeleitet von system_error
std::cerr << "Fehler: ";
if (e.code() == std::make_error_condition(std::io_errc::stream)) {
std::cerr << "stream\n";
} else {
std::cerr << "andere\n";
}
}
}
Godbolt Listing lst-0972-godb.cpp, https://godbolt.org/z/cjh93oPcr:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/cjh93oPcr
#include <iostream>
#include <system_error> // std::make_error_condition, std::ios_errc
int main () {
// umschalten auf Exceptions:
std::cin.exceptions (std::ios::failbit|std::ios::badbit);
try {
std::cin.rdbuf(nullptr); // löst eine Exception aus
} catch (std::ios::failure& e) { // abgeleitet von system_error
std::cerr << "Fehler: ";
if (e.code() == std::make_error_condition(std::io_errc::stream)) {
std::cerr << "stream\n";
} else {
std::cerr << "andere\n";
}
}
}
Listing 28.41: Nutzen Sie »typeindex« für verlässliche Typinformationen.
Book listing lst-0973-book.cpp:
// https://godbolt.org/z/x1dq1Wof6
#include <iostream>
#include <typeinfo>
#include <typeindex>
#include <map>
#include <string>
struct Base {
virtual ~Base() {}
};
struct Derived_One : public Base {};
struct Derived_Two : public Base {};
int main() {
using std::string; using std::cout; using std::type_index;
std::map<std::type_index, string> namen {
{ type_index(typeid(int)), "int" },
{ type_index(typeid(double)), "double" },
{ type_index(typeid(Base)), "Base" },
{ type_index(typeid(Derived_One)), "Derived_One" },
{ type_index(typeid(Derived_Two)), "Derived_Two" },
{ type_index(typeid(string)), "string" },
{ type_index(typeid(string::const_iterator)), "string" },
};
namen[type_index(typeid(namen))] = "namen-map";
int ganz;
double fliessend;
Base base{};
Base *one = new Derived_One{};
Base *two = new Derived_Two{};
// typeid.name() ist implementierungs- und laufzeitabhängig:
cout << typeid(ganz).name() << '\n'; // Bei mir: i
cout << typeid(fliessend).name() << '\n'; // Bei mir: d
cout << typeid(base).name() << '\n'; // Bei mir: 4Base
cout << typeid(*one).name() << '\n'; // Bei mir: 11Derived_One
cout << typeid(*two).name() << '\n'; // Bei mir: 11Derived_Two
cout << typeid(string).name() << '\n'; // Bei mir: Ss
cout << typeid(string{"Welt"}.begin()).name() << '\n';
// Bei mir: N9__gnu_cxx17__normal_iteratorIPcSsEE
cout << typeid(namen).name() << '\n';
// Bei mir: St3mapISt10type_indexSsSt4lessIS0_ESaISt4pairIKS0_SsEEE
cout << typeid(666/0).name() << '\n'; // Ausdruck wird nicht ausgeführt! Bei mir: i
// type_index macht type_infos vergleichbar:
cout << namen[type_index(typeid(ganz))] << '\n'; // Ausgabe: int
cout << namen[type_index(typeid(fliessend))] << '\n'; // Ausgabe: double
cout << namen[type_index(typeid(base))] << '\n'; // Ausgabe: Base
cout << namen[type_index(typeid(*one))] << '\n'; // Ausgabe: Derived_One
cout << namen[type_index(typeid(*two))] << '\n'; // Ausgabe: Derived_Two
cout << namen[type_index(typeid(string))] << '\n'; // Ausgabe: string
cout << namen[type_index(typeid(namen))] << '\n'; // Ausgabe: namen-map
}
Godbolt Listing lst-0973-godb.cpp, https://godbolt.org/z/x1dq1Wof6:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/x1dq1Wof6
#include <iostream>
#include <typeinfo>
#include <typeindex>
#include <map>
#include <string>
struct Base {
virtual ~Base() {}
};
struct Derived_One : public Base {};
struct Derived_Two : public Base {};
int main() {
using std::string; using std::cout; using std::type_index;
std::map<std::type_index, string> namen {
{ type_index(typeid(int)), "int" },
{ type_index(typeid(double)), "double" },
{ type_index(typeid(Base)), "Base" },
{ type_index(typeid(Derived_One)), "Derived_One" },
{ type_index(typeid(Derived_Two)), "Derived_Two" },
{ type_index(typeid(string)), "string" },
{ type_index(typeid(string::const_iterator)), "string" },
};
namen[type_index(typeid(namen))] = "namen-map";
int ganz;
double fliessend;
Base base{};
Base *one = new Derived_One{};
Base *two = new Derived_Two{};
// typeid.name() ist implementierungs- und laufzeitabhängig:
cout << typeid(ganz).name() << '\n'; // Bei mir: i
cout << typeid(fliessend).name() << '\n'; // Bei mir: d
cout << typeid(base).name() << '\n'; // Bei mir: 4Base
cout << typeid(*one).name() << '\n'; // Bei mir: 11Derived_One
cout << typeid(*two).name() << '\n'; // Bei mir: 11Derived_Two
cout << typeid(string).name() << '\n'; // Bei mir: Ss
cout << typeid(string{"Welt"}.begin()).name() << '\n';
// Bei mir: N9__gnu_cxx17__normal_iteratorIPcSsEE
cout << typeid(namen).name() << '\n';
// Bei mir: St3mapISt10type_indexSsSt4lessIS0_ESaISt4pairIKS0_SsEEE
cout << typeid(666/0).name() << '\n'; // Ausdruck wird nicht ausgeführt! Bei mir: i
// type_index macht type_infos vergleichbar:
cout << namen[type_index(typeid(ganz))] << '\n'; // Ausgabe: int
cout << namen[type_index(typeid(fliessend))] << '\n'; // Ausgabe: double
cout << namen[type_index(typeid(base))] << '\n'; // Ausgabe: Base
cout << namen[type_index(typeid(*one))] << '\n'; // Ausgabe: Derived_One
cout << namen[type_index(typeid(*two))] << '\n'; // Ausgabe: Derived_Two
cout << namen[type_index(typeid(string))] << '\n'; // Ausgabe: string
cout << namen[type_index(typeid(namen))] << '\n'; // Ausgabe: namen-map
}
Listing 28.42: Boosts »demangled_name« ist für die Ausgabe von Typnamen extrem nützlich.
Book listing lst-0974-book.cpp:
// https://godbolt.org/z/n54566cqT
#include <iostream>
#include <typeinfo>
#include <string>
#include <map>
#include <boost/core/typeinfo.hpp>
int main() {
using std::string; using std::cout;
std::map<int, string> namen;
int ganz;
double fliessend;
// demangled_name
using boost::core::demangled_name;
cout<<demangled_name(BOOST_CORE_TYPEID(ganz))<<'\n'; // Ausgabe: int
cout<<demangled_name(BOOST_CORE_TYPEID(fliessend))<<'\n'; // Ausgabe: double
cout<<demangled_name(BOOST_CORE_TYPEID(string))<<'\n'; // Ausgabe: std::string
cout<<demangled_name(BOOST_CORE_TYPEID(string{}.begin()))<<'\n';
// Ausgabe: __gnu_cxx::__normal_iterator<char*, std::string>
cout<<demangled_name(BOOST_CORE_TYPEID(namen))<<'\n';
// Ausgabe: std::map<int, std::string, std::less<int>,
// std::allocator<std::pair<int const, std::string> > >
cout<<demangled_name(BOOST_CORE_TYPEID(666/0))<<'\n'; // Ausgabe: int
}
Godbolt Listing lst-0974-godb.cpp, https://godbolt.org/z/n54566cqT:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/n54566cqT
#include <iostream>
#include <typeinfo>
#include <string>
#include <map>
#include <boost/core/typeinfo.hpp>
int main() {
using std::string; using std::cout;
std::map<int, string> namen;
int ganz;
double fliessend;
// demangled_name
using boost::core::demangled_name;
cout<<demangled_name(BOOST_CORE_TYPEID(ganz))<<'\n'; // Ausgabe: int
cout<<demangled_name(BOOST_CORE_TYPEID(fliessend))<<'\n'; // Ausgabe: double
cout<<demangled_name(BOOST_CORE_TYPEID(string))<<'\n'; // Ausgabe: std::string
cout<<demangled_name(BOOST_CORE_TYPEID(string{}.begin()))<<'\n';
// Ausgabe: __gnu_cxx::__normal_iterator<char*, std::string>
cout<<demangled_name(BOOST_CORE_TYPEID(namen))<<'\n';
// Ausgabe: std::map<int, std::string, std::less<int>,
// std::allocator<std::pair<int const, std::string> > >
cout<<demangled_name(BOOST_CORE_TYPEID(666/0))<<'\n'; // Ausgabe: int
}
GodboltId:Y3GsPd97d
Book listing lst-0976-book.cpp:
// https://godbolt.org/z/Y3GsPd97d
#include <set>
#include <string>
struct Drachen {
std::string name_;
};
namespace std {
template<> struct less<Drachen> { // Templatespezialisierung
bool operator()(const Drachen &lhs, const Drachen &rhs) const {
return lhs.name_ < rhs.name_;
} }; }
int main() {
std::set<Drachen> drachen {
Drachen{"Smaug"},Drachen{"Glaurung"},
Drachen{"Ancalagon"},Drachen{"Scatha"}};
}
Godbolt Listing lst-0976-godb.cpp, https://godbolt.org/z/Y3GsPd97d:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Y3GsPd97d
#include <set>
#include <string>
struct Drachen {
std::string name_;
};
namespace std {
template<> struct less<Drachen> { // Templatespezialisierung
bool operator()(const Drachen &lhs, const Drachen &rhs) const {
return lhs.name_ < rhs.name_;
} }; }
int main() {
std::set<Drachen> drachen {
Drachen{"Smaug"},Drachen{"Glaurung"},
Drachen{"Ancalagon"},Drachen{"Scatha"}};
}
Listing 28.43: Dieser Taschenrechner bildet Tasten auf Funktoren ab.
Book listing lst-0977-book.cpp:
// https://godbolt.org/z/j85P7b3oq
#include <string>
#include <vector>
#include <iostream>
#include <map>
#include <functional>
std::map<char,std::function<int(int,int)>> binOps { // zweistellige Operatoren
{'+', std::plus<int>{} },
{'-', std::minus<int>{} },
{'*', std::multiplies<int>{} },
{'/', std::divides<int>{} },
{'%', std::modulus<int>{} },
};
std::map<char,std::function<int(int)>> unOps { }; // einstellige Operatoren
auto val = [](auto n) { return [n](){ return n; };}; // gibt ein Lambda zurück
std::map<char,std::function<int()>> zeroOps { // nullstellige Operatoren
{'0', val(0)}, {'1', val(1)}, {'2', val(2)}, {'3', val(3)}, {'4', val(4)},
{'5', val(5)}, {'6', val(6)}, {'7', val(7)}, {'8', val(8)}, {'9', val(9)},
};
std::map<char,std::function<void(std::vector<int>&)>> stapelOps {
{ ' ', [](auto &stapel) { } }, // keine Operation
{ 'c', [](auto &stapel) { stapel.clear(); } }, // Stapel ganz löschen
{ ':', [](auto &stapel) { // obersten zwei Elemente vertauschen
auto top = stapel.back(); stapel.pop_back();
auto second = stapel.back(); stapel.pop_back();
stapel.push_back(top);
stapel.push_back(second);
} },
{ '=', [](auto &stapel) { // ganzen Stapel ausgeben
for(int elem : stapel) { std::cout << elem; }
std::cout << "\n";
} },
};
void rechner(std::string input) {
std::vector<int> stapel {};
for(char c : input) {
int top, second;
if(auto it = unOps.find(c); it != unOps.end()) {
// falls einstelliger Operator …
auto func = it->second;
top = stapel.back(); stapel.pop_back(); // … hole oberstes Element
stapel.push_back(func(top)); // … wende func an, Ergebnis auf Stapel
} else if(auto it = binOps.find(c); it != binOps.end()) {
// falls zweistelliger Operator …
auto func = it->second;
top = stapel.back(); stapel.pop_back(); // … hole die obersten 2 Elemente
second = stapel.back(); stapel.pop_back();
stapel.push_back(func(second, top)); // … wende func an, Ergebnis auf Stapel
} else if(auto it = zeroOps.find(c); it !=zeroOps.end()) {
// falls nullstelliger Operator …
auto func = it->second;
stapel.push_back(func()); // … Ergebnis von func auf Stapel
} else if(auto it = stapelOps.find(c); it !=stapelOps.end()) {
// falls Stapeloperator
auto func = it->second;
func(stapel); // … wende func auf Stapel an
} else {
std::cout << "\n'" << c << "' verstehe ich nicht.\n";
}
} /* for c */
}
int main(int argc, const char* argv[]) {
if(argc > 1) {
rechner(argv[1]);
} else {
// 3+4*5+6 mit Punkt- vor Strichrechnung ergibt 29
rechner("345*+6+=");
}
rechner("93-="); // 9 – 3 = Ausgabe: 6
rechner("82/="); // 8 / 2 = Ausgabe: 4
rechner("92%="); // 9 % 2 = Ausgabe: 1
}
Godbolt Listing lst-0977-godb.cpp, https://godbolt.org/z/j85P7b3oq:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/j85P7b3oq
#include <string>
#include <vector>
#include <iostream>
#include <map>
#include <functional>
std::map<char,std::function<int(int,int)>> binOps { // zweistellige Operatoren
{'+', std::plus<int>{} },
{'-', std::minus<int>{} },
{'*', std::multiplies<int>{} },
{'/', std::divides<int>{} },
{'%', std::modulus<int>{} },
};
std::map<char,std::function<int(int)>> unOps { }; // einstellige Operatoren
auto val = [](auto n) { return [n](){ return n; };}; // gibt ein Lambda zurück
std::map<char,std::function<int()>> zeroOps { // nullstellige Operatoren
{'0', val(0)}, {'1', val(1)}, {'2', val(2)}, {'3', val(3)}, {'4', val(4)},
{'5', val(5)}, {'6', val(6)}, {'7', val(7)}, {'8', val(8)}, {'9', val(9)},
};
std::map<char,std::function<void(std::vector<int>&)>> stapelOps {
{ ' ', [](auto &stapel) { } }, // keine Operation
{ 'c', [](auto &stapel) { stapel.clear(); } }, // Stapel ganz löschen
{ ':', [](auto &stapel) { // obersten zwei Elemente vertauschen
auto top = stapel.back(); stapel.pop_back();
auto second = stapel.back(); stapel.pop_back();
stapel.push_back(top);
stapel.push_back(second);
} },
{ '=', [](auto &stapel) { // ganzen Stapel ausgeben
for(int elem : stapel) { std::cout << elem; }
std::cout << "\n";
} },
};
void rechner(std::string input) {
std::vector<int> stapel {};
for(char c : input) {
int top, second;
if(auto it = unOps.find(c); it != unOps.end()) {
// falls einstelliger Operator …
auto func = it->second;
top = stapel.back(); stapel.pop_back(); // … hole oberstes Element
stapel.push_back(func(top)); // … wende func an, Ergebnis auf Stapel
} else if(auto it = binOps.find(c); it != binOps.end()) {
// falls zweistelliger Operator …
auto func = it->second;
top = stapel.back(); stapel.pop_back(); // … hole die obersten 2 Elemente
second = stapel.back(); stapel.pop_back();
stapel.push_back(func(second, top)); // … wende func an, Ergebnis auf Stapel
} else if(auto it = zeroOps.find(c); it !=zeroOps.end()) {
// falls nullstelliger Operator …
auto func = it->second;
stapel.push_back(func()); // … Ergebnis von func auf Stapel
} else if(auto it = stapelOps.find(c); it !=stapelOps.end()) {
// falls Stapeloperator
auto func = it->second;
func(stapel); // … wende func auf Stapel an
} else {
std::cout << "\n'" << c << "' verstehe ich nicht.\n";
}
} /* for c */
}
int main(int argc, const char* argv[]) {
if(argc > 1) {
rechner(argv[1]);
} else {
// 3+4*5+6 mit Punkt- vor Strichrechnung ergibt 29
rechner("345*+6+=");
}
rechner("93-="); // 9 – 3 = Ausgabe: 6
rechner("82/="); // 8 / 2 = Ausgabe: 4
rechner("92%="); // 9 % 2 = Ausgabe: 1
}
GodboltId:e6xT638ch
Book listing lst-0978-book.cpp:
// https://godbolt.org/z/e6xT638ch
#include <functional> // substract, minus, bind
#include <iostream>
using std::cout;
int substract(int a, int b) { return a - b; }
int main() {
using namespace std::placeholders;
cout << substract(9, 3) << '\n'; // Ausgabe: 6
auto minus3 = std::bind(substract, _1, 3);
cout << minus3(9) << '\n'; // Ausgabe: 6
auto von9 = std::bind(substract, 9, _1);
cout << von9(3) << '\n'; // Ausgabe: 6
auto nochmalMinus3 = std::bind(std::minus<int>{}, _1, 3);
cout << nochmalMinus3(9) << '\n'; // Ausgabe: 6
}
Godbolt Listing lst-0978-godb.cpp, https://godbolt.org/z/e6xT638ch:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/e6xT638ch
#include <functional> // substract, minus, bind
#include <iostream>
using std::cout;
int substract(int a, int b) { return a - b; }
int main() {
using namespace std::placeholders;
cout << substract(9, 3) << '\n'; // Ausgabe: 6
auto minus3 = std::bind(substract, _1, 3);
cout << minus3(9) << '\n'; // Ausgabe: 6
auto von9 = std::bind(substract, 9, _1);
cout << von9(3) << '\n'; // Ausgabe: 6
auto nochmalMinus3 = std::bind(std::minus<int>{}, _1, 3);
cout << nochmalMinus3(9) << '\n'; // Ausgabe: 6
}
Listing 28.44: Mit »bind« können Sie auch alle Parameter einer Funktion festlegen.
Book listing lst-0979-book.cpp:
// https://godbolt.org/z/xxfbGd9Ma
#include <random>
#include <vector>
#include <iostream>
#include <functional>
void wuerfel() {
std::default_random_engine engine{};
std::vector<size_t> counts{0,0,0,0,0,0};
std::uniform_int_distribution<int> w6{0, 5}; // gleichverteilte Ganzzahlen
auto w = std::bind(w6, engine); // w() = w6(engine)
for(auto i=1200*1000; i>0; --i) ++counts[w()];
for(auto c : counts) std::cout<<" "<<c;
std::cout << '\n';
}
int main() {
wuerfel();
}
Godbolt Listing lst-0979-godb.cpp, https://godbolt.org/z/xxfbGd9Ma:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/xxfbGd9Ma
#include <random>
#include <vector>
#include <iostream>
#include <functional>
void wuerfel() {
std::default_random_engine engine{};
std::vector<size_t> counts{0,0,0,0,0,0};
std::uniform_int_distribution<int> w6{0, 5}; // gleichverteilte Ganzzahlen
auto w = std::bind(w6, engine); // w() = w6(engine)
for(auto i=1200*1000; i>0; --i) ++counts[w()];
for(auto c : counts) std::cout<<" "<<c;
std::cout << '\n';
}
int main() {
wuerfel();
}
Listing 28.45: So machen Sie aus Klassenmitgliedern freie Funktionen.
Book listing lst-0982-book.cpp:
// https://godbolt.org/z/a3aTx7K7h
#include <functional>
#include <iostream>
struct Zahlen {
int dieZahl() {
return 42;
}
int mehr(int n) {
return n + data;
}
int data = 7;
};
int main() {
auto func = std::mem_fn(&Zahlen::dieZahl);
auto func2 = std::mem_fn(&Zahlen::mehr);
auto zugriff = std::mem_fn(&Zahlen::data);
Zahlen zahlen;
std::cout << func(zahlen) << '\n'; // Ausgabe: 42
std::cout << func2(zahlen, 66) << '\n'; // Ausgabe: 73
std::cout << zugriff(zahlen) << '\n'; // Ausgabe: 7
}
Godbolt Listing lst-0982-godb.cpp, https://godbolt.org/z/a3aTx7K7h:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/a3aTx7K7h
#include <functional>
#include <iostream>
struct Zahlen {
int dieZahl() {
return 42;
}
int mehr(int n) {
return n + data;
}
int data = 7;
};
int main() {
auto func = std::mem_fn(&Zahlen::dieZahl);
auto func2 = std::mem_fn(&Zahlen::mehr);
auto zugriff = std::mem_fn(&Zahlen::data);
Zahlen zahlen;
std::cout << func(zahlen) << '\n'; // Ausgabe: 42
std::cout << func2(zahlen, 66) << '\n'; // Ausgabe: 73
std::cout << zugriff(zahlen) << '\n'; // Ausgabe: 7
}
Listing 28.46: Basisfunktionalitäten von »variant«
Book listing lst-0983-book.cpp:
// https://godbolt.org/z/P8d494P6c
#include <variant>
using std::get;
int main() {
std::variant<int, float> v{};
v = 12; // Zustand wechselt auf int
auto i = get<int>(v); // holt den int
std::cout << i << '\n'; // Ausgabe: 12
v = 3.456f; // Zustand wechselt auf float
std::cout << get<float>(v) << '\n'; // Ausgabe: 3.456
get<double>(v); // (ERR) Fehler
get<3>(v); // (ERR) Fehler
std::variant<int, float> w{};
w = get<float>(v); // Zugriff über Typ
w = get<1>(v); // Zugriff geht auch über Index
w = v; // ganze Zuweisung geht auch
try {
get<int>(w); // löst Exception aus
} catch (std::bad_variant_access&) { /* ... */ }
}
Godbolt Listing lst-0983-godb.cpp, https://godbolt.org/z/P8d494P6c:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/P8d494P6c
#include <variant>
using std::get;
int main() {
std::variant<int, float> v{};
v = 12; // Zustand wechselt auf int
auto i = get<int>(v); // holt den int
std::cout << i << '\n'; // Ausgabe: 12
v = 3.456f; // Zustand wechselt auf float
std::cout << get<float>(v) << '\n'; // Ausgabe: 3.456
get<double>(v); // (ERR) Fehler
get<3>(v); // (ERR) Fehler
std::variant<int, float> w{};
w = get<float>(v); // Zugriff über Typ
w = get<1>(v); // Zugriff geht auch über Index
w = v; // ganze Zuweisung geht auch
try {
get<int>(w); // löst Exception aus
} catch (std::bad_variant_access&) { /* ... */ }
}
Listing 28.47: Einen »variant« per Visitor inspizieren
Book listing lst-0984-book.cpp:
// https://godbolt.org/z/ce3jETW6W
#include <variant>
#include <iostream>
using std::cout;
struct TypGruss {
void operator()(int) const { cout << "Hallo int"; }
void operator()(float) const { cout << "Servus float"; }
};
int main() {
std::variant<int, float> var{};
var = 12; // Zustand int
std::visit([](auto a) { cout << a; }, var); // generisches Lambda
cout << std::endl;
var = 3.456f; // Zustand float
std::visit(TypGruss{}, var); // Funktor mit Überladungen
cout << std::endl;
}
Godbolt Listing lst-0984-godb.cpp, https://godbolt.org/z/ce3jETW6W:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/ce3jETW6W
#include <variant>
#include <iostream>
using std::cout;
struct TypGruss {
void operator()(int) const { cout << "Hallo int"; }
void operator()(float) const { cout << "Servus float"; }
};
int main() {
std::variant<int, float> var{};
var = 12; // Zustand int
std::visit([](auto a) { cout << a; }, var); // generisches Lambda
cout << std::endl;
var = 3.456f; // Zustand float
std::visit(TypGruss{}, var); // Funktor mit Überladungen
cout << std::endl;
}
GodboltId:1eco9Wcr3
Book listing lst-0985-book.cpp:
// https://godbolt.org/z/1eco9Wcr3
#include <any>
#include <iostream>
#include <vector>
#include <string>
int main() {
std::any a = 5;
std::cout << std::any_cast<int>(a) << '\n';
a = 3.456;
std::cout << std::any_cast<double>(a) << '\n';
using namespace std::literals;
std::vector<std::any> data { 4, 8.976, "Geronimo"s };
std::cout << std::any_cast<double>( data[1] ) << '\n';
std::cout << data[1].type().name() << '\n';
}
Godbolt Listing lst-0985-godb.cpp, https://godbolt.org/z/1eco9Wcr3:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/1eco9Wcr3
#include <any>
#include <iostream>
#include <vector>
#include <string>
int main() {
std::any a = 5;
std::cout << std::any_cast<int>(a) << '\n';
a = 3.456;
std::cout << std::any_cast<double>(a) << '\n';
using namespace std::literals;
std::vector<std::any> data { 4, 8.976, "Geronimo"s };
std::cout << std::any_cast<double>( data[1] ) << '\n';
std::cout << data[1].type().name() << '\n';
}
GodboltId:r5PqK8M8o
Book listing lst-0988-book.cpp:
// https://godbolt.org/z/r5PqK8M8o
#include <charconv>
#include <vector>
#include <iostream>
#include <string>
std::vector<size_t> num_to_vec(const std::string& nums) {
std::vector<size_t> result {};
// ohne Leerzeichen am Ende
const auto end = nums.data() + nums.find_last_not_of( ' ' ) + 1;
const char* st = nullptr; // Zählpointer in der Schleife
auto last = nums.data(); // letztes nicht übersetztes Zeichen
size_t n; // konvertierte Zahl
do {
for(st = last; (st<end)&&(*st==' ' ); ++st); // überspringe ' '
if (last = std::from_chars(st, end, n).ptr; last != st)
result.push_back(n); // speichere Zahl
} while (last != st);
return result;
}
void fehlerDemo(const char* buf, size_t sz) {
int n;
auto [p, ec] = std::from_chars(buf, buf+sz, n);
if (ec != std::errc{}) {
const auto error = std::make_error_code(ec);
std::cout << error.message() << '\n';
}
}
int main() {
auto result = num_to_vec("12 33 43");
for(auto r : result) std::cout << r << " ";
std::cout << '\n';
// Ausgabe: 12 33 43
fehlerDemo("XYZ", 4);
// Ausgabe: Invalid argument
fehlerDemo("123123123123123", 16);
// Ausgabe: Numerical result out of range
}
Godbolt Listing lst-0988-godb.cpp, https://godbolt.org/z/r5PqK8M8o:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/r5PqK8M8o
#include <charconv>
#include <vector>
#include <iostream>
#include <string>
std::vector<size_t> num_to_vec(const std::string& nums) {
std::vector<size_t> result {};
// ohne Leerzeichen am Ende
const auto end = nums.data() + nums.find_last_not_of( ' ' ) + 1;
const char* st = nullptr; // Zählpointer in der Schleife
auto last = nums.data(); // letztes nicht übersetztes Zeichen
size_t n; // konvertierte Zahl
do {
for(st = last; (st<end)&&(*st==' ' ); ++st); // überspringe ' '
if (last = std::from_chars(st, end, n).ptr; last != st)
result.push_back(n); // speichere Zahl
} while (last != st);
return result;
}
void fehlerDemo(const char* buf, size_t sz) {
int n;
auto [p, ec] = std::from_chars(buf, buf+sz, n);
if (ec != std::errc{}) {
const auto error = std::make_error_code(ec);
std::cout << error.message() << '\n';
}
}
int main() {
auto result = num_to_vec("12 33 43");
for(auto r : result) std::cout << r << " ";
std::cout << '\n';
// Ausgabe: 12 33 43
fehlerDemo("XYZ", 4);
// Ausgabe: Invalid argument
fehlerDemo("123123123123123", 16);
// Ausgabe: Numerical result out of range
}
GodboltId:dcqenEd31
Book listing lst-0990-book.cpp:
// https://godbolt.org/z/dcqenEd31
#include <iostream>
#include <charconv>
#include <string_view>
#include <array>
int main() {
std::array<char, 10> str {};
if(auto [p, ec] = std::to_chars(str.data(), str.data() + str.size(), 42);
ec == std::errc{} )
std::cout << std::string_view(str.data(), p - str.data()) << "\n";
}
Godbolt Listing lst-0990-godb.cpp, https://godbolt.org/z/dcqenEd31:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/dcqenEd31
#include <iostream>
#include <charconv>
#include <string_view>
#include <array>
int main() {
std::array<char, 10> str {};
if(auto [p, ec] = std::to_chars(str.data(), str.data() + str.size(), 42);
ec == std::errc{} )
std::cout << std::string_view(str.data(), p - str.data()) << "\n";
}
Listing 29.1: So starten Sie einen Thread.
Book listing lst-0991-book.cpp:
// https://godbolt.org/z/qnadYPWh1
#include <iostream>
#include <thread>
using std::cout; using std::endl;
long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }
void aufgabe1() { auto r = fib(40); cout << "fib(40)=" << r << endl; }
void aufgabe2() { auto r = fib(41); cout << "fib(41)=" << r << endl; }
void aufgabe3() { auto r = fib(42); cout << "fib(42)=" << r << endl; }
struct HintergrundAufgabe {
void operator()() const {
aufgabe1();
aufgabe2();
aufgabe3();
}
};
int main() {
HintergrundAufgabe hintergrundAufgabe{}; // Initialisierung, berechnet noch nichts
std::jthread meinThread{ hintergrundAufgabe }; // Berechnung startet
}
Godbolt Listing lst-0991-godb.cpp, https://godbolt.org/z/qnadYPWh1:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/qnadYPWh1
#include <iostream>
#include <thread>
using std::cout; using std::endl;
long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }
void aufgabe1() { auto r = fib(40); cout << "fib(40)=" << r << endl; }
void aufgabe2() { auto r = fib(41); cout << "fib(41)=" << r << endl; }
void aufgabe3() { auto r = fib(42); cout << "fib(42)=" << r << endl; }
struct HintergrundAufgabe {
void operator()() const {
aufgabe1();
aufgabe2();
aufgabe3();
}
};
int main() {
HintergrundAufgabe hintergrundAufgabe{}; // Initialisierung, berechnet noch nichts
std::jthread meinThread{ hintergrundAufgabe }; // Berechnung startet
}
GodboltId:nPGY47r4K
Book listing lst-0993-book.cpp:
// https://godbolt.org/z/nPGY47r4K
std::jthread meinThread{ [] {
aufgabe1();
aufgabe2();
aufgabe3();
} };
Godbolt Listing lst-0993-godb.cpp, https://godbolt.org/z/nPGY47r4K:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/nPGY47r4K
std::jthread meinThread{ [] {
aufgabe1();
aufgabe2();
aufgabe3();
} };
Listing 29.2: Mit »stop_token« kommuniziert die Außenwelt in den Thread hinein.
Book listing lst-0994-book.cpp:
// https://godbolt.org/z/6cqd7Tsae
struct HintergrundAufgabe {
void operator()(std::stop_token st) const { // Token fürs Kommunizieren
aufgabe1();
if(st.stop_requested()) return;
aufgabe2();
if(st.stop_requested()) return;
aufgabe3();
}
};
int main() {
HintergrundAufgabe hintergrundAufgabe{};
std::jthread meinThread{ hintergrundAufgabe };
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // warte 100ms
meinThread.request_stop(); // bitte den Thread, sich zu beenden
}
Godbolt Listing lst-0994-godb.cpp, https://godbolt.org/z/6cqd7Tsae:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/6cqd7Tsae
struct HintergrundAufgabe {
void operator()(std::stop_token st) const { // Token fürs Kommunizieren
aufgabe1();
if(st.stop_requested()) return;
aufgabe2();
if(st.stop_requested()) return;
aufgabe3();
}
};
int main() {
HintergrundAufgabe hintergrundAufgabe{};
std::jthread meinThread{ hintergrundAufgabe };
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // warte 100ms
meinThread.request_stop(); // bitte den Thread, sich zu beenden
}
GodboltId:Tzs93MzfK
Book listing lst-0995-book.cpp:
// https://godbolt.org/z/Tzs93MzfK
std::thread meinThread{ [] { // purer Thread
aufgabe1();
aufgabe2();
aufgabe3();
} };
meinThread.join(); // wartet auf das Ende des Threads
Godbolt Listing lst-0995-godb.cpp, https://godbolt.org/z/Tzs93MzfK:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Tzs93MzfK
std::thread meinThread{ [] { // purer Thread
aufgabe1();
aufgabe2();
aufgabe3();
} };
meinThread.join(); // wartet auf das Ende des Threads
GodboltId:1jhrx1MMn
Book listing lst-0996-book.cpp:
// https://godbolt.org/z/1jhrx1MMn
#include <iostream>
#include <thread>
#include <vector>
#include <exception>
using std::cout; using std::endl;
long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }
void aufgabe1() { auto r = fib(40); cout << "fib(40)=" << r << endl; }
void hauptprogramm() {
try {
std::thread th{ &aufgabe1 };
std::vector data{ 0,1,2 };
data.at(666); // (ERR) löst out_of_range aus
th.join(); // würde warten
} catch(std::runtime_error &ex) { // (ERR) passt nicht auf out_of_range
/*...*/
}
}
int main() {
try {
hauptprogramm();
} catch( ... ) { // so weit, so gut, sieht sicher aus
std::cout << "Ein Fehler ist aufgetreten\n"; // bekommen Sie nicht zu Gesicht
}
}
Godbolt Listing lst-0996-godb.cpp, https://godbolt.org/z/1jhrx1MMn:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/1jhrx1MMn
#include <iostream>
#include <thread>
#include <vector>
#include <exception>
using std::cout; using std::endl;
long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }
void aufgabe1() { auto r = fib(40); cout << "fib(40)=" << r << endl; }
void hauptprogramm() {
try {
std::thread th{ &aufgabe1 };
std::vector data{ 0,1,2 };
data.at(666); // (ERR) löst out_of_range aus
th.join(); // würde warten
} catch(std::runtime_error &ex) { // (ERR) passt nicht auf out_of_range
/*...*/
}
}
int main() {
try {
hauptprogramm();
} catch( ... ) { // so weit, so gut, sieht sicher aus
std::cout << "Ein Fehler ist aufgetreten\n"; // bekommen Sie nicht zu Gesicht
}
}
GodboltId:1aj16d7Ga
Book listing lst-0997-book.cpp:
// https://godbolt.org/z/1aj16d7Ga
#include <iostream>
#include <thread>
#include <vector>
#include <exception>
using std::cout; using std::endl;
long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }
void aufgabe1() { auto r = fib(40); cout << "fib(40)=" << r << endl; }
void hauptprogramm() {
std::thread th{ &aufgabe1 };
try {
std::vector data{ 0,1,2 };
data.at(666); // (ERR) löst out_of_range aus
} catch(std::runtime_error &ex) { // passt nicht auf out_of_range
/* ... */ // speziellen Fehler hier behandeln
} catch( ... ) {
th.join();
throw; // Fehlerbehandlung außen fortsetzen
}
th.join(); // wartet nach Okay oder speziellem Fehler
}
int main() {
try {
hauptprogramm();
} catch( ... ) {
std::cout << "Ein Fehler ist aufgetreten\n";
}
}
Godbolt Listing lst-0997-godb.cpp, https://godbolt.org/z/1aj16d7Ga:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/1aj16d7Ga
#include <iostream>
#include <thread>
#include <vector>
#include <exception>
using std::cout; using std::endl;
long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }
void aufgabe1() { auto r = fib(40); cout << "fib(40)=" << r << endl; }
void hauptprogramm() {
std::thread th{ &aufgabe1 };
try {
std::vector data{ 0,1,2 };
data.at(666); // (ERR) löst out_of_range aus
} catch(std::runtime_error &ex) { // passt nicht auf out_of_range
/* ... */ // speziellen Fehler hier behandeln
} catch( ... ) {
th.join();
throw; // Fehlerbehandlung außen fortsetzen
}
th.join(); // wartet nach Okay oder speziellem Fehler
}
int main() {
try {
hauptprogramm();
} catch( ... ) {
std::cout << "Ein Fehler ist aufgetreten\n";
}
}
GodboltId:8TdzEGf3d
Book listing lst-0998-book.cpp:
// https://godbolt.org/z/8TdzEGf3d
void hauptprogramm() {
std::jthread th{ &aufgabe1 };
std::vector data{ 0,1,2 };
data.at(666); // (ERR) löst out_of_range aus
}
Godbolt Listing lst-0998-godb.cpp, https://godbolt.org/z/8TdzEGf3d:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/8TdzEGf3d
void hauptprogramm() {
std::jthread th{ &aufgabe1 };
std::vector data{ 0,1,2 };
data.at(666); // (ERR) löst out_of_range aus
}
Listing 29.3: Parameter an die Threadfunktion fügen Sie dem Konstruktor hinzu.
Book listing lst-0999-book.cpp:
// https://godbolt.org/z/PP4GT3oc6
#include <iostream>
#include <thread>
using std::cout; using std::endl;
long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }
void runFib(long n) {
auto r = fib(n);
cout << "fib("<<n<<")=" << r << endl;
}
long ack(long m, long n) { // Ackermannfunktion
if(m==0) return n+1;
if(n==0) return ack(m-1, 1);
return ack(m - 1, ack(m, n-1));
}
void runAck(long m, long n) {
auto r = ack(m, n);
cout << "ack("<<m<<','<<n<<")=" << r << endl;
}
int main() {
std::jthread f40{ runFib, 40 };
std::jthread f41{ runFib, 41 };
std::jthread f42{ runFib, 42 };
f40.join(); f41.join(); f42.join();
std::thread a1{ runAck, 4, 0 };
std::thread a2{ runAck, 4, 1 };
std::thread a3{ runAck, 2, 700 };
std::thread a4{ runAck, 3, 10 };
}
Godbolt Listing lst-0999-godb.cpp, https://godbolt.org/z/PP4GT3oc6:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/PP4GT3oc6
#include <iostream>
#include <thread>
using std::cout; using std::endl;
long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }
void runFib(long n) {
auto r = fib(n);
cout << "fib("<<n<<")=" << r << endl;
}
long ack(long m, long n) { // Ackermannfunktion
if(m==0) return n+1;
if(n==0) return ack(m-1, 1);
return ack(m - 1, ack(m, n-1));
}
void runAck(long m, long n) {
auto r = ack(m, n);
cout << "ack("<<m<<','<<n<<")=" << r << endl;
}
int main() {
std::jthread f40{ runFib, 40 };
std::jthread f41{ runFib, 41 };
std::jthread f42{ runFib, 42 };
f40.join(); f41.join(); f42.join();
std::thread a1{ runAck, 4, 0 };
std::thread a2{ runAck, 4, 1 };
std::thread a3{ runAck, 2, 700 };
std::thread a4{ runAck, 3, 10 };
}
Listing 29.4: Parameter werden in den Thread kopiert.
Book listing lst-1000-book.cpp:
// https://godbolt.org/z/fbnbKzrs1
#include <iostream>
#include <thread>
#include <chrono>
using namespace std::chrono; // seconds, suffix s
void delayPrint(seconds s, const std::string& msg) {
std::this_thread::sleep_for(s);
std::cout << msg << std::endl;
}
int main() {
std::jthread m1{ delayPrint, 1s, "Auf die Plaetze" };
std::jthread m2{ delayPrint, 2s, std::string{"fertig"} };
std::string los = "los";
std::jthread m3{ delayPrint, 3s, los };
}
Godbolt Listing lst-1000-godb.cpp, https://godbolt.org/z/fbnbKzrs1:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/fbnbKzrs1
#include <iostream>
#include <thread>
#include <chrono>
using namespace std::chrono; // seconds, suffix s
void delayPrint(seconds s, const std::string& msg) {
std::this_thread::sleep_for(s);
std::cout << msg << std::endl;
}
int main() {
std::jthread m1{ delayPrint, 1s, "Auf die Plaetze" };
std::jthread m2{ delayPrint, 2s, std::string{"fertig"} };
std::string los = "los";
std::jthread m3{ delayPrint, 3s, los };
}
Listing 29.5: Achtung mit rohen Zeigern als Parameter
Book listing lst-1001-book.cpp:
// https://godbolt.org/z/hvq5dbzde
#include <iostream>
#include <thread>
#include <chrono>
using namespace std::chrono; // seconds, suffix s
void delayPrint(seconds s, const char* msg) { // (ERR) roher Zeiger
std::this_thread::sleep_for(s);
std::cout << msg << std::endl; // (ERR) das klappt nicht
}
void lauf() {
const char risiko[] = "Das geht nicht gut...";
std::jthread m{ delayPrint, 1s, risiko }; // (ERR) roher Zeiger
m.detach();
// hier wird der Bereich von 'risiko' verlassen
}
int main() {
lauf();
std::this_thread::sleep_for(2s); // noch 2 Sekunden warten
}
Godbolt Listing lst-1001-godb.cpp, https://godbolt.org/z/hvq5dbzde:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/hvq5dbzde
#include <iostream>
#include <thread>
#include <chrono>
using namespace std::chrono; // seconds, suffix s
void delayPrint(seconds s, const char* msg) { // (ERR) roher Zeiger
std::this_thread::sleep_for(s);
std::cout << msg << std::endl; // (ERR) das klappt nicht
}
void lauf() {
const char risiko[] = "Das geht nicht gut...";
std::jthread m{ delayPrint, 1s, risiko }; // (ERR) roher Zeiger
m.detach();
// hier wird der Bereich von 'risiko' verlassen
}
int main() {
lauf();
std::this_thread::sleep_for(2s); // noch 2 Sekunden warten
}
Listing 29.6: Mit ref eine Referenz erzwingen
Book listing lst-1002-book.cpp:
// https://godbolt.org/z/GnsWYvecv
#include <iostream>
#include <thread>
#include <chrono>
using namespace std::chrono; // seconds, suffix s
struct Zustand {
int zaehler;
};
void zeigeZustand(const Zustand& zustand) {
for(auto i : { 5,4,3,2,1 }) {
std::cout << "zaehler: " << zustand.zaehler << std::endl;
std::this_thread::sleep_for(1s);
}
}
int main() {
Zustand zustand { 4 };
std::jthread th{zeigeZustand, std::ref(zustand)}; // bleibt Referenz auf zustand
std::this_thread::sleep_for(1s);
zustand.zaehler = 501;
std::this_thread::sleep_for(1s);
zustand.zaehler = 87;
std::this_thread::sleep_for(1s);
zustand.zaehler = 2;
}
Godbolt Listing lst-1002-godb.cpp, https://godbolt.org/z/GnsWYvecv:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/GnsWYvecv
#include <iostream>
#include <thread>
#include <chrono>
using namespace std::chrono; // seconds, suffix s
struct Zustand {
int zaehler;
};
void zeigeZustand(const Zustand& zustand) {
for(auto i : { 5,4,3,2,1 }) {
std::cout << "zaehler: " << zustand.zaehler << std::endl;
std::this_thread::sleep_for(1s);
}
}
int main() {
Zustand zustand { 4 };
std::jthread th{zeigeZustand, std::ref(zustand)}; // bleibt Referenz auf zustand
std::this_thread::sleep_for(1s);
zustand.zaehler = 501;
std::this_thread::sleep_for(1s);
zustand.zaehler = 87;
std::this_thread::sleep_for(1s);
zustand.zaehler = 2;
}
Listing 29.7: Mit move Eingaben in den Thread verschieben
Book listing lst-1003-book.cpp:
// https://godbolt.org/z/j5Y15Esx7
// … includes …
#include <thread>
using namespace std::chrono; // seconds, suffix s
struct Image {
std::vector<char> data_; // Kopie teuer
explicit Image() : data_(1'000'000) {}
};
void zeigeImage(Image img) {
std::cout << img.data_.size() << '\n';
}
void zeigeIptr(std::unique_ptr<int> iptr) {
std::cout << *iptr << '\n';
}
int main() {
// teuer zu kopieren, aber dafür gut zu verschieben:
Image image{};
std::cout << image.data_.size() << std::endl; // Ausgabe: 1000000
std::jthread th1{ zeigeImage, std::move(image) };// Ausgabe: 1000000
std::this_thread::sleep_for(1s);
std::cout << image.data_.size() << std::endl; // Ausgabe: 0
th1.join(); // explizit warten, bis der Thread fertig ist
// unmöglich zu kopieren, aber gut zu verschieben:
auto iptr = std::make_unique<int>( 657 );
std::cout << (bool)iptr << std::endl; // Ausgabe: 1 für wahr
std::jthread th2{ zeigeIptr, std::move(iptr) }; // Ausgabe: 657
std::this_thread::sleep_for(1s);
std::cout << (bool)iptr.get() << std::endl; // Ausgabe: 0 für falsch
}
Godbolt Listing lst-1003-godb.cpp, https://godbolt.org/z/j5Y15Esx7:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/j5Y15Esx7
// … includes …
#include <thread>
using namespace std::chrono; // seconds, suffix s
struct Image {
std::vector<char> data_; // Kopie teuer
explicit Image() : data_(1'000'000) {}
};
void zeigeImage(Image img) {
std::cout << img.data_.size() << '\n';
}
void zeigeIptr(std::unique_ptr<int> iptr) {
std::cout << *iptr << '\n';
}
int main() {
// teuer zu kopieren, aber dafür gut zu verschieben:
Image image{};
std::cout << image.data_.size() << std::endl; // Ausgabe: 1000000
std::jthread th1{ zeigeImage, std::move(image) };// Ausgabe: 1000000
std::this_thread::sleep_for(1s);
std::cout << image.data_.size() << std::endl; // Ausgabe: 0
th1.join(); // explizit warten, bis der Thread fertig ist
// unmöglich zu kopieren, aber gut zu verschieben:
auto iptr = std::make_unique<int>( 657 );
std::cout << (bool)iptr << std::endl; // Ausgabe: 1 für wahr
std::jthread th2{ zeigeIptr, std::move(iptr) }; // Ausgabe: 657
std::this_thread::sleep_for(1s);
std::cout << (bool)iptr.get() << std::endl; // Ausgabe: 0 für falsch
}
Listing 29.8: Einen Thread zurückgeben
Book listing lst-1004-book.cpp:
// https://godbolt.org/z/Kv84eb96E
#include <iostream>
#include <thread>
#include <chrono>
using namespace std::chrono; // seconds, suffix s
auto makeThread(std::string wer) {
return std::jthread{ [wer] {
std::this_thread::sleep_for(1s);
std::cout << "Viel Glueck, " << wer << std::endl;
} };
}
int main() {
auto th = makeThread("Jim"); // Ausgabe: Viel Glueck, Jim
th.join();
}
Godbolt Listing lst-1004-godb.cpp, https://godbolt.org/z/Kv84eb96E:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Kv84eb96E
#include <iostream>
#include <thread>
#include <chrono>
using namespace std::chrono; // seconds, suffix s
auto makeThread(std::string wer) {
return std::jthread{ [wer] {
std::this_thread::sleep_for(1s);
std::cout << "Viel Glueck, " << wer << std::endl;
} };
}
int main() {
auto th = makeThread("Jim"); // Ausgabe: Viel Glueck, Jim
th.join();
}
Listing 29.9: Einen Thread verschieben
Book listing lst-1005-book.cpp:
// https://godbolt.org/z/39x4bafco
#include <thread>
#include <chrono>
using namespace std::chrono; // seconds, suffix s
void kobraUebernehmenSie(std::jthread job) {
job.join();
}
int main() {
std::jthread th{ [] {
std::this_thread::sleep_for(1s);
std::cout << "Viel Glueck, Dan" << std::endl;
} };
kobraUebernehmenSie( std::move(th) ); // Zuständigkeit übertragen
}
Godbolt Listing lst-1005-godb.cpp, https://godbolt.org/z/39x4bafco:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/39x4bafco
#include <thread>
#include <chrono>
using namespace std::chrono; // seconds, suffix s
void kobraUebernehmenSie(std::jthread job) {
job.join();
}
int main() {
std::jthread th{ [] {
std::this_thread::sleep_for(1s);
std::cout << "Viel Glueck, Dan" << std::endl;
} };
kobraUebernehmenSie( std::move(th) ); // Zuständigkeit übertragen
}
Listing 29.10: Threads im Container
Book listing lst-1006-book.cpp:
// https://godbolt.org/z/YrEPnYMaP
#include <iostream>
#include <thread>
#include <vector>
using std::cout; using std::endl;
long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }
void runFib(long n) { auto r = fib(n); cout << "fib("<<n<<")=" << r << endl; }
int main() {
std::vector<std::jthread> threads;
// starten
for( auto n : { 38, 39, 40, 41, 42, 43, }) {
threads.emplace_back( runFib, n );
}
}
Godbolt Listing lst-1006-godb.cpp, https://godbolt.org/z/YrEPnYMaP:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/YrEPnYMaP
#include <iostream>
#include <thread>
#include <vector>
using std::cout; using std::endl;
long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }
void runFib(long n) { auto r = fib(n); cout << "fib("<<n<<")=" << r << endl; }
int main() {
std::vector<std::jthread> threads;
// starten
for( auto n : { 38, 39, 40, 41, 42, 43, }) {
threads.emplace_back( runFib, n );
}
}
Listing 29.11: Parallelität der Hardware herausfinden
Book listing lst-1009-book.cpp:
// https://godbolt.org/z/Gen1rfEn6
#include <thread>
#include <iostream>
#include <vector>
#include <chrono> // steady_clock
using std::cout; using std::endl; using namespace std::chrono;
long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }
int main() {
cout << std::thread::hardware_concurrency() << '\n';
for(int nthreads : { 1,2,3,4,5,6 }) {
cout << "Threads: ";
const auto start = steady_clock::now();
std::vector<std::jthread> threads;
for(int ti = 1; ti <= nthreads; ++ti) {
threads.emplace_back( std::jthread{fib, 40});
cout << ti << "... "; cout.flush();
}
for(auto &th : threads) th.join(); // explizit joinen vor der Zeitmessung
const auto now = steady_clock::now();
cout << " Zeit: " << duration_cast<milliseconds>(
now-start).count()<<"ms\n";
}
}
Godbolt Listing lst-1009-godb.cpp, https://godbolt.org/z/Gen1rfEn6:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Gen1rfEn6
#include <thread>
#include <iostream>
#include <vector>
#include <chrono> // steady_clock
using std::cout; using std::endl; using namespace std::chrono;
long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }
int main() {
cout << std::thread::hardware_concurrency() << '\n';
for(int nthreads : { 1,2,3,4,5,6 }) {
cout << "Threads: ";
const auto start = steady_clock::now();
std::vector<std::jthread> threads;
for(int ti = 1; ti <= nthreads; ++ti) {
threads.emplace_back( std::jthread{fib, 40});
cout << ti << "... "; cout.flush();
}
for(auto &th : threads) th.join(); // explizit joinen vor der Zeitmessung
const auto now = steady_clock::now();
cout << " Zeit: " << duration_cast<milliseconds>(
now-start).count()<<"ms\n";
}
}
Listing 29.12: Jeder Thread hat eine Kennung.
Book listing lst-1010-book.cpp:
// https://godbolt.org/z/TM6c7cdss
#include <thread>
#include <iostream>
int main() {
std::cout << "Main: " << std::this_thread::get_id() << '\n';
std::jthread th{ []{
std::cout << "Thread: " << std::this_thread::get_id() << '\n';
}};
}
Godbolt Listing lst-1010-godb.cpp, https://godbolt.org/z/TM6c7cdss:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/TM6c7cdss
#include <thread>
#include <iostream>
int main() {
std::cout << "Main: " << std::this_thread::get_id() << '\n';
std::jthread th{ []{
std::cout << "Thread: " << std::this_thread::get_id() << '\n';
}};
}
Listing 29.13: Ein klassisches Data Race
Book listing lst-1011-book.cpp:
// https://godbolt.org/z/7GEs9a4n6
#include <thread>
#include <iostream>
int count = 0; // wird simultan verändert
void run() {
for(int i=0; i<1'000'000; ++i) {
count += 1; // ungeschützt
}
}
int main() {
std::cout << "Start: " << count << '\n'; // Ausgabe: Start: 0
std::thread th1{ run };
std::thread th2{ run };
std::thread th3{ run };
th1.join(); th2.join(); th3.join();
std::cout << "Ende: " << count << '\n'; // Ausgabe sicher nicht: 3000000
}
Godbolt Listing lst-1011-godb.cpp, https://godbolt.org/z/7GEs9a4n6:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/7GEs9a4n6
#include <thread>
#include <iostream>
int count = 0; // wird simultan verändert
void run() {
for(int i=0; i<1'000'000; ++i) {
count += 1; // ungeschützt
}
}
int main() {
std::cout << "Start: " << count << '\n'; // Ausgabe: Start: 0
std::thread th1{ run };
std::thread th2{ run };
std::thread th3{ run };
th1.join(); th2.join(); th3.join();
std::cout << "Ende: " << count << '\n'; // Ausgabe sicher nicht: 3000000
}
Listing 29.14: Gutartige Data Races sind auch undefiniert.
Book listing lst-1012-book.cpp:
// https://godbolt.org/z/v3b6sxEab
#include <thread>
/* exakte Zählung nicht so wichtig */
int count = 0; // wird simultan verändert
void run() {
for(int i=0; i<1'000; ++i) {
count += 1; // ungeschützt
if(count > 1000) return; // (ERR) Endbedingung
for(int j=0; j<1'000; ++j)
;
}
}
int main() {
std::thread th1{ run };
std::thread th2{ run };
std::thread th3{ run };
th1.join(); th2.join(); th3.join();
}
Godbolt Listing lst-1012-godb.cpp, https://godbolt.org/z/v3b6sxEab:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/v3b6sxEab
#include <thread>
/* exakte Zählung nicht so wichtig */
int count = 0; // wird simultan verändert
void run() {
for(int i=0; i<1'000; ++i) {
count += 1; // ungeschützt
if(count > 1000) return; // (ERR) Endbedingung
for(int j=0; j<1'000; ++j)
;
}
}
int main() {
std::thread th1{ run };
std::thread th2{ run };
std::thread th3{ run };
th1.join(); th2.join(); th3.join();
}
Listing 29.15: Latches können herunterzählen und warten.
Book listing lst-1013-book.cpp:
// https://godbolt.org/z/rrfn4d5WP
#include <thread>
#include <latch>
#include <iostream>
long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }
int main() {
std::latch la{ 3 }; // wir erwarten 3 Threads
std::jthread th1{ [&la] { fib(39); la.count_down(); } };
std::jthread th2{ [&la] { fib(38); la.count_down(); } };
std::jthread th3{ [&la] { fib(40); la.count_down(); } };
fib(37); // Hauptthread
std::cout << "Haupthread: fertig\n";
la.wait(); // wartet bis la == 0
std::cout << "Rest fertig\n";
}
Godbolt Listing lst-1013-godb.cpp, https://godbolt.org/z/rrfn4d5WP:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/rrfn4d5WP
#include <thread>
#include <latch>
#include <iostream>
long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }
int main() {
std::latch la{ 3 }; // wir erwarten 3 Threads
std::jthread th1{ [&la] { fib(39); la.count_down(); } };
std::jthread th2{ [&la] { fib(38); la.count_down(); } };
std::jthread th3{ [&la] { fib(40); la.count_down(); } };
fib(37); // Hauptthread
std::cout << "Haupthread: fertig\n";
la.wait(); // wartet bis la == 0
std::cout << "Rest fertig\n";
}
Listing 29.16: Eine Barriere wartet auf eine bestimmte Anzahl von Threads.
Book listing lst-1014-book.cpp:
// https://godbolt.org/z/d3dc1Tsj8
#include <thread>
#include <barrier>
#include <iostream>
#include <vector>
long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }
constexpr int anz = 8; // 8 Worker
constexpr int max_n = 32; // bis 32 berechnen
std::vector<long> ergebnisse(anz); // Puffer: Platz für 8 Ergebnisse
void ausgeben() { // Signalisierungsfunktion druckt Puffer
for (auto n : ergebnisse) std::cout << n << ' ';
std::cout << '\n';
}
std::barrier ba{anz, ausgeben}; // immer nach 8 ausgeben
void worker(std::stop_token st, int idx) {
// n = 0, 9, 17, 25, … ; 1, 10, 18, 26, …
for(int n = idx; n<max_n; n += anz) {
if(st.stop_requested()) return;
ergebnisse[idx] = fib(n); // schreibe Ergebnis in Puffer
ba.arrive_and_wait(); // warte, bis 8 Threads hier sind
}
}
int main() {
std::vector<std::jthread> threads; // 8 Threads
for (int idx=0; idx<anz; ++idx) {
threads.emplace_back(worker, idx); // erzeuge Thread mit Index
}
for (auto& t : threads) t.join(); // warte, bis alle fertig sind
}
Godbolt Listing lst-1014-godb.cpp, https://godbolt.org/z/d3dc1Tsj8:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/d3dc1Tsj8
#include <thread>
#include <barrier>
#include <iostream>
#include <vector>
long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }
constexpr int anz = 8; // 8 Worker
constexpr int max_n = 32; // bis 32 berechnen
std::vector<long> ergebnisse(anz); // Puffer: Platz für 8 Ergebnisse
void ausgeben() { // Signalisierungsfunktion druckt Puffer
for (auto n : ergebnisse) std::cout << n << ' ';
std::cout << '\n';
}
std::barrier ba{anz, ausgeben}; // immer nach 8 ausgeben
void worker(std::stop_token st, int idx) {
// n = 0, 9, 17, 25, … ; 1, 10, 18, 26, …
for(int n = idx; n<max_n; n += anz) {
if(st.stop_requested()) return;
ergebnisse[idx] = fib(n); // schreibe Ergebnis in Puffer
ba.arrive_and_wait(); // warte, bis 8 Threads hier sind
}
}
int main() {
std::vector<std::jthread> threads; // 8 Threads
for (int idx=0; idx<anz; ++idx) {
threads.emplace_back(worker, idx); // erzeuge Thread mit Index
}
for (auto& t : threads) t.join(); // warte, bis alle fertig sind
}
Listing 29.17: Ein Mutex zusammen mit einem einfachen Lock
Book listing lst-1015-book.cpp:
// https://godbolt.org/z/3fz5a4vYv
#include <mutex> // mutex, lock_guard
#include <list>
#include <algorithm> // find
using std::lock_guard; using std::mutex; using std::find;
class MxIntList {
std::list <int> data_;
mutable mutex mx_;
public:
void add(int value) {
lock_guard guard{mx_}; // schützt bis Ende der Methode
data_.push_back(value);
}
bool contains(int searchVal) const {
lock_guard guard{mx_}; // schützt bis Ende der Methode
return find(data_.begin(), data_.end(), searchVal) != data_.end();
}
};
Godbolt Listing lst-1015-godb.cpp, https://godbolt.org/z/3fz5a4vYv:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/3fz5a4vYv
#include <mutex> // mutex, lock_guard
#include <list>
#include <algorithm> // find
using std::lock_guard; using std::mutex; using std::find;
class MxIntList {
std::list <int> data_;
mutable mutex mx_;
public:
void add(int value) {
lock_guard guard{mx_}; // schützt bis Ende der Methode
data_.push_back(value);
}
bool contains(int searchVal) const {
lock_guard guard{mx_}; // schützt bis Ende der Methode
return find(data_.begin(), data_.end(), searchVal) != data_.end();
}
};
Listing 29.18: Die Schnittstelle zu einem multithreadfähigen Stack
Book listing lst-1016-book.cpp:
// https://godbolt.org/z/4j7njd763
#include <vector>
template<class T>
class MxStack {
public:
bool isEmpty() const;
void push(const T&);
void pop();
const T& top() const;
};
Godbolt Listing lst-1016-godb.cpp, https://godbolt.org/z/4j7njd763:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/4j7njd763
#include <vector>
template<class T>
class MxStack {
public:
bool isEmpty() const;
void push(const T&);
void pop();
const T& top() const;
};
Listing 29.19: Problematischer Code für den MxStack
Book listing lst-1017-book.cpp:
// https://godbolt.org/z/1boeTMMvf
MxStack<int> mxs{};
// …
// mehr Code
// …
if( ! mxs.isEmpty()) { // (ERR) nicht sicher
const auto value = mxs.top(); // (ERR) nicht sicher
mxs.pop(); // (ERR) nicht sicher
// …
// mehr Code
// …
}
Godbolt Listing lst-1017-godb.cpp, https://godbolt.org/z/1boeTMMvf:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/1boeTMMvf
MxStack<int> mxs{};
// …
// mehr Code
// …
if( ! mxs.isEmpty()) { // (ERR) nicht sicher
const auto value = mxs.top(); // (ERR) nicht sicher
mxs.pop(); // (ERR) nicht sicher
// …
// mehr Code
// …
}
Listing 29.20: Eine Möglichkeit, wie zwei Threads obigen Code ausführen könnten
Book listing lst-1018-book.cpp:
/* Thread 1 */ /* Thread 2 */
if( ! mxs.isEmpty()) {
if( ! mxs.isEmpty()) {
const auto value = mxs.top();
const auto value = mxs.top();
mxs.pop();
// … mehr Code …
mxs.pop();
// … mehr Code …
Listing 29.21: Ein sehr einfacher threadsicherer Stack
Book listing lst-1019-book.cpp:
// https://godbolt.org/z/xGv9drh73
#include <vector>
#include <thread>
#include <mutex>
#include <iostream>
#include <numeric> // iota
/* T: noexcept kopier- und zuweisbar */
template<typename T>
class MxStack {
std::vector<T> data_;
std::mutex mx_;
public:
MxStack() : data_{} {}
bool isEmpty() const { return data_.empty(); }
void push(const T& val) {
std::lock_guard<std::mutex> g{mx_};
data_.push_back(val);
}
T pop() {
std::lock_guard g{mx_};
if(data_.empty())
throw std::length_error{"empty stack"};
T tmp{std::move(data_.back())};
data_.pop_back();
return tmp;
}
};
int main() {
// Stack vorbereiten
MxStack<int> mxs{};
for(int i=1; i<=1'000'000; ++i) mxs.push(i);
// Berechnung definieren
auto sumIt = [&mxs](long &sum) {
int val{};
try {
while( ! mxs.isEmpty()) {
sum += mxs.pop(); // könnte immer noch werfen
}
} catch(std::length_error &ex) {}
};
// Berechnen
long sum1 = 0; // fürs Teilergebnis
std::jthread th1{sumIt, std::ref(sum1)};
long sum2 = 0; // fürs Teilergebnis
std::thread th2{sumIt, std::ref(sum2)};
th1.join(); th2.join();
long sum = sum1 + sum2; // Gesamtergebnis
// Ergebnis
std::cout << "Sollergebnis: "
<< (1'000'000L*1'000'001)/2 << '\n'; // Ausgabe: 500000500000
std::cout << "Tatsaechlich: "
<< sum << '\n'; // Ausgabe: 500000500000
}
Godbolt Listing lst-1019-godb.cpp, https://godbolt.org/z/xGv9drh73:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/xGv9drh73
#include <vector>
#include <thread>
#include <mutex>
#include <iostream>
#include <numeric> // iota
/* T: noexcept kopier- und zuweisbar */
template<typename T>
class MxStack {
std::vector<T> data_;
std::mutex mx_;
public:
MxStack() : data_{} {}
bool isEmpty() const { return data_.empty(); }
void push(const T& val) {
std::lock_guard<std::mutex> g{mx_};
data_.push_back(val);
}
T pop() {
std::lock_guard g{mx_};
if(data_.empty())
throw std::length_error{"empty stack"};
T tmp{std::move(data_.back())};
data_.pop_back();
return tmp;
}
};
int main() {
// Stack vorbereiten
MxStack<int> mxs{};
for(int i=1; i<=1'000'000; ++i) mxs.push(i);
// Berechnung definieren
auto sumIt = [&mxs](long &sum) {
int val{};
try {
while( ! mxs.isEmpty()) {
sum += mxs.pop(); // könnte immer noch werfen
}
} catch(std::length_error &ex) {}
};
// Berechnen
long sum1 = 0; // fürs Teilergebnis
std::jthread th1{sumIt, std::ref(sum1)};
long sum2 = 0; // fürs Teilergebnis
std::thread th2{sumIt, std::ref(sum2)};
th1.join(); th2.join();
long sum = sum1 + sum2; // Gesamtergebnis
// Ergebnis
std::cout << "Sollergebnis: "
<< (1'000'000L*1'000'001)/2 << '\n'; // Ausgabe: 500000500000
std::cout << "Tatsaechlich: "
<< sum << '\n'; // Ausgabe: 500000500000
}
Listing 29.22: »swap« für »MxStack«
Book listing lst-1022-book.cpp:
// https://godbolt.org/z/9PMcz1cqP
friend void swap(MxStack& re, MxStack& li) {
if(&re==&li) return; // Adresse dieselbe? Mit sich selbst tauschen unnötig
std::lock( re.mx_, li.mx_ ); // mehrere Sperren gleichzeitig
std::lock_guard lkre{re.mx_, std::adopt_lock}; // schon gesperrt
std::lock_guard lkli{li.mx_, std::adopt_lock}; // schon gesperrt
std::swap(li.data_, re.data_); // vertauschen ausführen
}
Godbolt Listing lst-1022-godb.cpp, https://godbolt.org/z/9PMcz1cqP:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/9PMcz1cqP
friend void swap(MxStack& re, MxStack& li) {
if(&re==&li) return; // Adresse dieselbe? Mit sich selbst tauschen unnötig
std::lock( re.mx_, li.mx_ ); // mehrere Sperren gleichzeitig
std::lock_guard lkre{re.mx_, std::adopt_lock}; // schon gesperrt
std::lock_guard lkli{li.mx_, std::adopt_lock}; // schon gesperrt
std::swap(li.data_, re.data_); // vertauschen ausführen
}
Listing 29.23: Mutexe kann man transferieren.
Book listing lst-1023-book.cpp:
// https://godbolt.org/z/e7rraPGx4
#include <thread>
#include <mutex>
#include <vector>
#include <numeric> // accumulate, iota
using std::mutex; using std::unique_lock;
std::vector<int> myData; // geteilte Daten
mutex myMutex; // Mutex zu den Daten
unique_lock<mutex> bereiteDatenVor() {
unique_lock lk1{myMutex}; // sperren
myData.resize(1000);
std::iota(myData.begin(), myData.end(), 1); // 1..1000
return lk1; // Sperre transferieren
}
int verarbeiteDaten() {
unique_lock lk2 = bereiteDatenVor(); // Sperre transferiert
return std::accumulate(myData.begin(), myData.end(), 0);
}
Godbolt Listing lst-1023-godb.cpp, https://godbolt.org/z/e7rraPGx4:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/e7rraPGx4
#include <thread>
#include <mutex>
#include <vector>
#include <numeric> // accumulate, iota
using std::mutex; using std::unique_lock;
std::vector<int> myData; // geteilte Daten
mutex myMutex; // Mutex zu den Daten
unique_lock<mutex> bereiteDatenVor() {
unique_lock lk1{myMutex}; // sperren
myData.resize(1000);
std::iota(myData.begin(), myData.end(), 1); // 1..1000
return lk1; // Sperre transferieren
}
int verarbeiteDaten() {
unique_lock lk2 = bereiteDatenVor(); // Sperre transferiert
return std::accumulate(myData.begin(), myData.end(), 0);
}
Listing 29.24: Späte Initialisierung mit nur einem Thread
Book listing lst-1024-book.cpp:
// https://godbolt.org/z/T7vehq58b
std::shared_ptr<BigData> bigData{};
BigData& getBigData() {
if(!bigData) bigData.reset(new BigData{});
return *bigData;
}
int useBigData() {
auto bigData = getBigData();
// bigData->…
}
Godbolt Listing lst-1024-godb.cpp, https://godbolt.org/z/T7vehq58b:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/T7vehq58b
std::shared_ptr<BigData> bigData{};
BigData& getBigData() {
if(!bigData) bigData.reset(new BigData{});
return *bigData;
}
int useBigData() {
auto bigData = getBigData();
// bigData->…
}
Listing 29.25: Späte Initialisierung mit mehreren Threads
Book listing lst-1025-book.cpp:
// https://godbolt.org/z/3vcnzfqfM
#include <mutex> // once_flag, call_once
std::shared_ptr<BigData> bigData{};
std::once_flag bigDataInitFlag;
void initBigData() {
bigData = std::make_shared<BigData>();
}
int useBigData() {
std::call_once(bigDataInitFlag, initBigData);
// bigData->…
}
Godbolt Listing lst-1025-godb.cpp, https://godbolt.org/z/3vcnzfqfM:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/3vcnzfqfM
#include <mutex> // once_flag, call_once
std::shared_ptr<BigData> bigData{};
std::once_flag bigDataInitFlag;
void initBigData() {
bigData = std::make_shared<BigData>();
}
int useBigData() {
std::call_once(bigDataInitFlag, initBigData);
// bigData->…
}
Listing 29.26: Späte Initialisierung kann auch innerhalb eines Threads nützlich sein.
Book listing lst-1026-book.cpp:
// https://godbolt.org/z/TcsrefEPh
#include <mutex> // once_flag, call_once
#include <memory>
struct Connection {
void csend(const char *data) {} // dummy
const char* crecv() {} // dummy
};
class Sender {
std::shared_ptr<Connection> conn_;
std::once_flag connInitFlag_;
void open() {
conn_.reset( new Connection{} );
}
public:
void send(const char* data) {
std::call_once(connInitFlag_, &Sender::open, this); // Methodenzeiger
conn_->csend(data);
}
const char* recv() {
std::call_once(connInitFlag_, [this] {this->open();} ); // Lambda
return conn_->crecv();
}
};
Godbolt Listing lst-1026-godb.cpp, https://godbolt.org/z/TcsrefEPh:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/TcsrefEPh
#include <mutex> // once_flag, call_once
#include <memory>
struct Connection {
void csend(const char *data) {} // dummy
const char* crecv() {} // dummy
};
class Sender {
std::shared_ptr<Connection> conn_;
std::once_flag connInitFlag_;
void open() {
conn_.reset( new Connection{} );
}
public:
void send(const char* data) {
std::call_once(connInitFlag_, &Sender::open, this); // Methodenzeiger
conn_->csend(data);
}
const char* recv() {
std::call_once(connInitFlag_, [this] {this->open();} ); // Lambda
return conn_->crecv();
}
};
Listing 29.27: Es sind Vorkehrungen nötig, wenn ein Mutex mehrmals gesperrt werden soll.
Book listing lst-1027-book.cpp:
// https://godbolt.org/z/38qMMWoz6
#include <mutex> // recursive_mutex
#include <iostream>
struct MulDiv {
std::recursive_mutex mx_;
int value_;
explicit MulDiv(int value) : value_{value} {}
void mul(int x) {
std::lock_guard lk1(mx_); // innen
value_ *= x;
}
void div(int x) {
std::lock_guard lk2(mx_); // innen
value_ /= x;
}
void muldiv(int x, int y){
std::lock_guard lk3(mx_); // außen
mul(x);
div(y);
}
};
int main() {
MulDiv m{42}; // 3*7*2 *5
m.muldiv(5, 15);
std::cout << m.value_ << '\n'; // Ausgabe: 14
}
Godbolt Listing lst-1027-godb.cpp, https://godbolt.org/z/38qMMWoz6:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/38qMMWoz6
#include <mutex> // recursive_mutex
#include <iostream>
struct MulDiv {
std::recursive_mutex mx_;
int value_;
explicit MulDiv(int value) : value_{value} {}
void mul(int x) {
std::lock_guard lk1(mx_); // innen
value_ *= x;
}
void div(int x) {
std::lock_guard lk2(mx_); // innen
value_ /= x;
}
void muldiv(int x, int y){
std::lock_guard lk3(mx_); // außen
mul(x);
div(y);
}
};
int main() {
MulDiv m{42}; // 3*7*2 *5
m.muldiv(5, 15);
std::cout << m.value_ << '\n'; // Ausgabe: 14
}
Listing 29.28: Speicher nur für den aktuellen Thread
Book listing lst-1028-book.cpp:
// https://godbolt.org/z/1j8W7GjTf
#include <iostream>
#include <string>
#include <thread>
#include <mutex>
thread_local unsigned int usage = 0;
static std::mutex cout_mutex;
void use(const std::string thread_name) {
++usage;
std::lock_guard lock(cout_mutex); // Ausgabe schützen
std::cout << thread_name << ": " << usage << '\n';
}
int main() {
std::jthread a{use, "a"}, b{use, "b"};
use("main");
}
Godbolt Listing lst-1028-godb.cpp, https://godbolt.org/z/1j8W7GjTf:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/1j8W7GjTf
#include <iostream>
#include <string>
#include <thread>
#include <mutex>
thread_local unsigned int usage = 0;
static std::mutex cout_mutex;
void use(const std::string thread_name) {
++usage;
std::lock_guard lock(cout_mutex); // Ausgabe schützen
std::cout << thread_name << ": " << usage << '\n';
}
int main() {
std::jthread a{use, "a"}, b{use, "b"};
use("main");
}
Listing 29.29: Zwei Threads kommunizieren über eine Bedingungsvariable.
Book listing lst-1030-book.cpp:
// https://godbolt.org/z/af6jK9dKo
#include <thread>
#include <mutex>
#include <condition_variable>
#include <vector>
#include <deque>
#include <iostream>
#include <syncstream> // osyncstream
std::deque<int> g_data{}; // Datenaustausch zwischen Threads
std::condition_variable g_condvar; // benachrichtigen
std::mutex g_mx; // schützt g_data während Veränderungen
void produziere(int limit) {
std::vector prims{2}; // bisherige Prims als Prüfteiler
for(int kandidat=3; kandidat < limit; kandidat+=2) {
for(int teiler : prims) {
if(teiler*teiler > kandidat) { // kandidat ist prim
std::lock_guard lk{g_mx}; // data schützen
g_data.push_back(kandidat); // füllen
g_condvar.notify_one(); // benachrichtigen
prims.push_back(kandidat); // für interne Berechnungen
break; // nächster Prim-Kandidat
} else if(kandidat % teiler == 0) { // nicht prim
break; // nächster Prim-Kandidat
} else {
// nächster Prüfteiler
}
}
}
// ganze Arbeit fertig mitteilen
std::lock_guard lk{g_mx}; // data schützen
g_data.push_back(0); // mit Endemarkierung füllen
g_condvar.notify_all(); // benachrichtigen
}
void konsumiere(char l, char r) {
while(true) { // für immer
std::unique_lock lk{g_mx};
g_condvar.wait(lk, []{ return !g_data.empty();});
int prim = g_data.front(); // Daten holen
if(prim == 0) return; // fertig; 0 drin lassen für andere Konsumenten
g_data.pop_front();
lk.unlock(); // Sperre freigeben
std::osyncstream osync{std::cout}; // Ausgabe synchronisieren
osync << l << prim << r <<' ';
}
}
int main() {
// ein Produzent:
std::jthread thProd{produziere, 1'000};
// drei Konsumenten
std::jthread thKon1{konsumiere, '[', ']' };
std::jthread thKon2{konsumiere, '<', '>' };
std::jthread thKon3{konsumiere, '{', '}' };
// warten und beenden
thProd.join();
thKon1.join(); thKon2.join(); thKon3.join();
std::cout << '\n';
}
Godbolt Listing lst-1030-godb.cpp, https://godbolt.org/z/af6jK9dKo:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/af6jK9dKo
#include <thread>
#include <mutex>
#include <condition_variable>
#include <vector>
#include <deque>
#include <iostream>
#include <syncstream> // osyncstream
std::deque<int> g_data{}; // Datenaustausch zwischen Threads
std::condition_variable g_condvar; // benachrichtigen
std::mutex g_mx; // schützt g_data während Veränderungen
void produziere(int limit) {
std::vector prims{2}; // bisherige Prims als Prüfteiler
for(int kandidat=3; kandidat < limit; kandidat+=2) {
for(int teiler : prims) {
if(teiler*teiler > kandidat) { // kandidat ist prim
std::lock_guard lk{g_mx}; // data schützen
g_data.push_back(kandidat); // füllen
g_condvar.notify_one(); // benachrichtigen
prims.push_back(kandidat); // für interne Berechnungen
break; // nächster Prim-Kandidat
} else if(kandidat % teiler == 0) { // nicht prim
break; // nächster Prim-Kandidat
} else {
// nächster Prüfteiler
}
}
}
// ganze Arbeit fertig mitteilen
std::lock_guard lk{g_mx}; // data schützen
g_data.push_back(0); // mit Endemarkierung füllen
g_condvar.notify_all(); // benachrichtigen
}
void konsumiere(char l, char r) {
while(true) { // für immer
std::unique_lock lk{g_mx};
g_condvar.wait(lk, []{ return !g_data.empty();});
int prim = g_data.front(); // Daten holen
if(prim == 0) return; // fertig; 0 drin lassen für andere Konsumenten
g_data.pop_front();
lk.unlock(); // Sperre freigeben
std::osyncstream osync{std::cout}; // Ausgabe synchronisieren
osync << l << prim << r <<' ';
}
}
int main() {
// ein Produzent:
std::jthread thProd{produziere, 1'000};
// drei Konsumenten
std::jthread thKon1{konsumiere, '[', ']' };
std::jthread thKon2{konsumiere, '<', '>' };
std::jthread thKon3{konsumiere, '{', '}' };
// warten und beenden
thProd.join();
thKon1.join(); thKon2.join(); thKon3.join();
std::cout << '\n';
}
Listing 29.30: »async« kann einfach asynchrone Berechnungen anstoßen.
Book listing lst-1035-book.cpp:
// https://godbolt.org/z/Gh9Y5srd7
#include <iostream>
#include <future> // async
using std::cout; using std::endl;
long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }
int main() {
auto f40 = std::async(fib, 40);
auto f41 = std::async(fib, 41);
auto f42 = std::async(fib, 42);
auto f43 = std::async(fib, 43);
/* ... an dieser Stelle können weitere Berechnungen stehen ... */
cout << "fib(40): " << f40.get() << endl; // Ausgabe: fib(40): 102334155
cout << "fib(41): " << f41.get() << endl; // Ausgabe: fib(41): 165580141
cout << "fib(42): " << f42.get() << endl; // Ausgabe: fib(42): 267914296
cout << "fib(43): " << f43.get() << endl; // Ausgabe: fib(43): 433494437
}
Godbolt Listing lst-1035-godb.cpp, https://godbolt.org/z/Gh9Y5srd7:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Gh9Y5srd7
#include <iostream>
#include <future> // async
using std::cout; using std::endl;
long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }
int main() {
auto f40 = std::async(fib, 40);
auto f41 = std::async(fib, 41);
auto f42 = std::async(fib, 42);
auto f43 = std::async(fib, 43);
/* ... an dieser Stelle können weitere Berechnungen stehen ... */
cout << "fib(40): " << f40.get() << endl; // Ausgabe: fib(40): 102334155
cout << "fib(41): " << f41.get() << endl; // Ausgabe: fib(41): 165580141
cout << "fib(42): " << f42.get() << endl; // Ausgabe: fib(42): 267914296
cout << "fib(43): " << f43.get() << endl; // Ausgabe: fib(43): 433494437
}
Listing 29.31: Es ist in Ordnung, ein Ergebnis nicht abzuholen.
Book listing lst-1036-book.cpp:
// https://godbolt.org/z/7Mea1Y3Mn
#include <iostream>
#include <future> // async
using std::cout; using std::endl;
long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }
int main() {
auto f40 = std::async(fib, 40);
auto f41 = std::async(fib, 41);
auto f42 = std::async(fib, 42);
auto f43 = std::async(fib, 43);
cout << "fib(40): " << f40.get() << endl; // Ausgabe: fib(40): 102334155
} // wartet auch auf f41, f42 und f43.
Godbolt Listing lst-1036-godb.cpp, https://godbolt.org/z/7Mea1Y3Mn:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/7Mea1Y3Mn
#include <iostream>
#include <future> // async
using std::cout; using std::endl;
long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }
int main() {
auto f40 = std::async(fib, 40);
auto f41 = std::async(fib, 41);
auto f42 = std::async(fib, 42);
auto f43 = std::async(fib, 43);
cout << "fib(40): " << f40.get() << endl; // Ausgabe: fib(40): 102334155
} // wartet auch auf f41, f42 und f43.
Listing 29.32: So erzwingen Sie die verzögerte Ausführung.
Book listing lst-1037-book.cpp:
// https://godbolt.org/z/P9MjGe6Mn
#include <iostream>
#include <future> // async
#include <vector>
using std::cout; using std::endl;
long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }
int main() {
// Aufgaben vorbereiten
std::vector< std::future<long> > fibs;
for(int n=0; n<50; ++n) {
auto fut = std::async(std::launch::deferred, fib, n);
fibs.push_back( std::move(fut) );
}
// nur das benötigte Ergebnis abholen
cout << "fib(42): " << fibs[42].get() << endl; // Ausgabe: fib(42): 267914296
}
Godbolt Listing lst-1037-godb.cpp, https://godbolt.org/z/P9MjGe6Mn:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/P9MjGe6Mn
#include <iostream>
#include <future> // async
#include <vector>
using std::cout; using std::endl;
long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }
int main() {
// Aufgaben vorbereiten
std::vector< std::future<long> > fibs;
for(int n=0; n<50; ++n) {
auto fut = std::async(std::launch::deferred, fib, n);
fibs.push_back( std::move(fut) );
}
// nur das benötigte Ergebnis abholen
cout << "fib(42): " << fibs[42].get() << endl; // Ausgabe: fib(42): 267914296
}
Listing 29.33: Warten für eine gewisse Zeit bei »async«
Book listing lst-1038-book.cpp:
// https://godbolt.org/z/o9oYrvMcj
#include <iostream>
#include <future> // async
#include <chrono>
using std::cout; using std::endl; using namespace std::chrono;
long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }
int main() {
auto f43 = std::async(fib, 43);
while(true) {
auto fertig = f43.wait_for(500ms);
if(fertig==std::future_status::timeout) {
std::cout << "noch nicht..." << std::endl;
} else {
break;
}
}
// abholen, ist sofort da
cout << "fib(43): " << f43.get() << endl; // Ausgabe: fib(43): 701408733
}
Godbolt Listing lst-1038-godb.cpp, https://godbolt.org/z/o9oYrvMcj:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/o9oYrvMcj
#include <iostream>
#include <future> // async
#include <chrono>
using std::cout; using std::endl; using namespace std::chrono;
long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }
int main() {
auto f43 = std::async(fib, 43);
while(true) {
auto fertig = f43.wait_for(500ms);
if(fertig==std::future_status::timeout) {
std::cout << "noch nicht..." << std::endl;
} else {
break;
}
}
// abholen, ist sofort da
cout << "fib(43): " << f43.get() << endl; // Ausgabe: fib(43): 701408733
}
Listing 29.34: Warten auf einen Lock mit einem »timed_mutex«
Book listing lst-1039-book.cpp:
// https://godbolt.org/z/xzY8hj9oP
#include <chrono>
#include <future>
#include <mutex>
#include <vector>
#include <iostream>
std::timed_mutex mtx;
long fibX(long n) { return n < 2L ? 1L : fibX(n-1L) + fibX(n-2L); }
long fibCall(long n) {
using namespace std::chrono; // Suffixe
if(mtx.try_lock_for(1000ms)) {
auto res = fibX(n);
mtx.unlock();
return res;
} else {
return 0L;
}
}
int main() {
std::vector< std::future<long> > fs;
for(long n=1; n<= 42; ++n) {
fs.emplace_back( std::async(std::launch::async, fibCall, n) );
}
for(auto &f : fs) {
std::cout << f.get() << " ";
}
std::cout << std::endl;
}
Godbolt Listing lst-1039-godb.cpp, https://godbolt.org/z/xzY8hj9oP:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/xzY8hj9oP
#include <chrono>
#include <future>
#include <mutex>
#include <vector>
#include <iostream>
std::timed_mutex mtx;
long fibX(long n) { return n < 2L ? 1L : fibX(n-1L) + fibX(n-2L); }
long fibCall(long n) {
using namespace std::chrono; // Suffixe
if(mtx.try_lock_for(1000ms)) {
auto res = fibX(n);
mtx.unlock();
return res;
} else {
return 0L;
}
}
int main() {
std::vector< std::future<long> > fs;
for(long n=1; n<= 42; ++n) {
fs.emplace_back( std::async(std::launch::async, fibCall, n) );
}
for(auto &f : fs) {
std::cout << f.get() << " ";
}
std::cout << std::endl;
}
Listing 29.35: Exceptions kommen erst bei »get« beim äußeren Thread an.
Book listing lst-1040-book.cpp:
// https://godbolt.org/z/Pj63xfn7x
#include <future> // async
#include <vector>
#include <algorithm> // max
#include <iostream>
int berechneHoehe(int count, int maxCount, int scale) {
if(maxCount == 0)
throw std::logic_error("Alle Hoehen 0");
return (count * scale) / maxCount;
}
void balken(const std::vector<int> &counts) {
// Berechnung starten
auto maxCount = *std::max_element(counts.begin(), counts.end());
std::vector< std::future<int> > futs;
for(int count : counts) {
futs.push_back(
std::async(std::launch::async,
berechneHoehe, count, maxCount, 200) );
}
// Ergebnisse einsammeln
for(auto &fut : futs) {
std::cout << fut.get() << ' '; // löst Exception aus
}
std::cout << '\n';
}
int main() {
try {
balken(std::vector {10,23,13,0,33,4 }); // Ausgabe: 60 139 78 0 200 24
balken(std::vector { 0, 0, 0, 0 }); // löst Exception aus
} catch(std::exception &ex) {
std::cout << "Fehler: " << ex.what() << '\n'; // Ausgabe: Fehler: Alle Hoehen 0
}
}
Godbolt Listing lst-1040-godb.cpp, https://godbolt.org/z/Pj63xfn7x:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Pj63xfn7x
#include <future> // async
#include <vector>
#include <algorithm> // max
#include <iostream>
int berechneHoehe(int count, int maxCount, int scale) {
if(maxCount == 0)
throw std::logic_error("Alle Hoehen 0");
return (count * scale) / maxCount;
}
void balken(const std::vector<int> &counts) {
// Berechnung starten
auto maxCount = *std::max_element(counts.begin(), counts.end());
std::vector< std::future<int> > futs;
for(int count : counts) {
futs.push_back(
std::async(std::launch::async,
berechneHoehe, count, maxCount, 200) );
}
// Ergebnisse einsammeln
for(auto &fut : futs) {
std::cout << fut.get() << ' '; // löst Exception aus
}
std::cout << '\n';
}
int main() {
try {
balken(std::vector {10,23,13,0,33,4 }); // Ausgabe: 60 139 78 0 200 24
balken(std::vector { 0, 0, 0, 0 }); // löst Exception aus
} catch(std::exception &ex) {
std::cout << "Fehler: " << ex.what() << '\n'; // Ausgabe: Fehler: Alle Hoehen 0
}
}
Listing 29.36: Nur das »get« muss in »try« gekapselt werden.
Book listing lst-1041-book.cpp:
// https://godbolt.org/z/ndc4f8T3P
#include <future> // async
#include <iostream>
int berechneHoehe(int count, int maxCount, int scale) {
if(maxCount == 0)
throw std::logic_error("maxCount ist 0");
return (count * scale) / maxCount;
}
int main() {
auto fut = std::async(std::launch::async, berechneHoehe, 0, 0, 200); // (ERR) wirft
try {
std::cout << fut.get() << '\n'; // löst Exception aus
} catch(std::exception &ex) {
std::cout << "Fehler: " << ex.what() << '\n'; // Ausgabe: Fehler: maxCount ist 0
}
}
Godbolt Listing lst-1041-godb.cpp, https://godbolt.org/z/ndc4f8T3P:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/ndc4f8T3P
#include <future> // async
#include <iostream>
int berechneHoehe(int count, int maxCount, int scale) {
if(maxCount == 0)
throw std::logic_error("maxCount ist 0");
return (count * scale) / maxCount;
}
int main() {
auto fut = std::async(std::launch::async, berechneHoehe, 0, 0, 200); // (ERR) wirft
try {
std::cout << fut.get() << '\n'; // löst Exception aus
} catch(std::exception &ex) {
std::cout << "Fehler: " << ex.what() << '\n'; // Ausgabe: Fehler: maxCount ist 0
}
}
Listing 29.37: »future« und »promise« arbeiten zusammen.
Book listing lst-1043-book.cpp:
// https://godbolt.org/z/9Ys4s5qjs
#include <future>
#include <thread>
#include <iostream>
#include <exception>
int ack(int m, int n); // Ackermannfunktion
void langeBerechnung(std::promise<int> intPromise) {
try {
int result = ack(3,12);
intPromise.set_value(result); // Ergebnis mitteilen
} catch (std::exception &e) {
intPromise.set_exception(make_exception_ptr(e)); // Exception mitteilen
} catch ( ... ) {
intPromise.set_exception(std::current_exception()); // Exc. ohne Namen
}
}
int main () {
std::promise<int> intPromise; // Promise erzeugen
std::future<int> intFuture = intPromise.get_future(); // Future anfordern
std::jthread th{ langeBerechnung, // starten
std::move(intPromise) }; // Promise übergeben
th.detach(); // weiterlaufen lassen
// könnte eine Exception werfen:
int result = intFuture.get(); // Ergebnis anfordern
std::cout << result << std::endl;
}
Godbolt Listing lst-1043-godb.cpp, https://godbolt.org/z/9Ys4s5qjs:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/9Ys4s5qjs
#include <future>
#include <thread>
#include <iostream>
#include <exception>
int ack(int m, int n); // Ackermannfunktion
void langeBerechnung(std::promise<int> intPromise) {
try {
int result = ack(3,12);
intPromise.set_value(result); // Ergebnis mitteilen
} catch (std::exception &e) {
intPromise.set_exception(make_exception_ptr(e)); // Exception mitteilen
} catch ( ... ) {
intPromise.set_exception(std::current_exception()); // Exc. ohne Namen
}
}
int main () {
std::promise<int> intPromise; // Promise erzeugen
std::future<int> intFuture = intPromise.get_future(); // Future anfordern
std::jthread th{ langeBerechnung, // starten
std::move(intPromise) }; // Promise übergeben
th.detach(); // weiterlaufen lassen
// könnte eine Exception werfen:
int result = intFuture.get(); // Ergebnis anfordern
std::cout << result << std::endl;
}
Listing 29.38: Packaged Task vorbereiten für die spätere Ausführung
Book listing lst-1044-book.cpp:
// https://godbolt.org/z/9s94nbrx3
#include <future>
#include <thread>
#include <iostream>
int ack(int m, int n); // Ackermannfunktion
int main () {
std::packaged_task<int(void)> task1 { // Signatur der Restfunktion
[]{ return ack(3,11);} }; // ack(3,11) vorbereiten
auto f1 = task1.get_future(); // Kommunikationskanal
std::jthread th1 { move(task1) }; // in neuen Thread
std::cout << " ack(3,11):" << f1.get() // Ergebnis abholen
<< '\n'; // Ausgabe: ack(3,11):16381
}
Godbolt Listing lst-1044-godb.cpp, https://godbolt.org/z/9s94nbrx3:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/9s94nbrx3
#include <future>
#include <thread>
#include <iostream>
int ack(int m, int n); // Ackermannfunktion
int main () {
std::packaged_task<int(void)> task1 { // Signatur der Restfunktion
[]{ return ack(3,11);} }; // ack(3,11) vorbereiten
auto f1 = task1.get_future(); // Kommunikationskanal
std::jthread th1 { move(task1) }; // in neuen Thread
std::cout << " ack(3,11):" << f1.get() // Ergebnis abholen
<< '\n'; // Ausgabe: ack(3,11):16381
}
Listing 29.39: Packaged Task erst später mit Argumenten versorgen
Book listing lst-1045-book.cpp:
// https://godbolt.org/z/bq1hn5rjo
#include <future>
#include <thread>
#include <iostream>
int ack(int m, int n); // Ackermannfunktion
int main () {
std::packaged_task<int(int,int)> task2 { &ack }; // andere Signatur
auto f2 = task2.get_future();
std::jthread th2 { move(task2), 3, 12 }; // Parameter hier
std::cout << " ack(3,12):" << f2.get() << '\n'; // Ausgabe: ack(3,12):32765
th2.join();
}
Godbolt Listing lst-1045-godb.cpp, https://godbolt.org/z/bq1hn5rjo:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/bq1hn5rjo
#include <future>
#include <thread>
#include <iostream>
int ack(int m, int n); // Ackermannfunktion
int main () {
std::packaged_task<int(int,int)> task2 { &ack }; // andere Signatur
auto f2 = task2.get_future();
std::jthread th2 { move(task2), 3, 12 }; // Parameter hier
std::cout << " ack(3,12):" << f2.get() << '\n'; // Ausgabe: ack(3,12):32765
th2.join();
}
Listing 29.40: So finden Sie heraus, ob die Operationen sperrfrei sind.
Book listing lst-1046-book.cpp:
// https://godbolt.org/z/3Y5WP6qWM
#include <iostream>
#include <atomic>
struct CArray { int a[100]; };
struct Einfach { int x, y; };
int main() {
std::atomic<CArray> carray{};
std::cout << (carray.is_lock_free() ? "sperrfrei" : "sperrt")
<< '\n'; // Ausgabe: sperrt
std::atomic<Einfach> einfach{};
std::cout << (einfach.is_lock_free() ? "sperrfrei" : "sperrt")
<< '\n'; // Ausgabe: sperrfrei
}
Godbolt Listing lst-1046-godb.cpp, https://godbolt.org/z/3Y5WP6qWM:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/3Y5WP6qWM
#include <iostream>
#include <atomic>
struct CArray { int a[100]; };
struct Einfach { int x, y; };
int main() {
std::atomic<CArray> carray{};
std::cout << (carray.is_lock_free() ? "sperrfrei" : "sperrt")
<< '\n'; // Ausgabe: sperrt
std::atomic<Einfach> einfach{};
std::cout << (einfach.is_lock_free() ? "sperrfrei" : "sperrt")
<< '\n'; // Ausgabe: sperrfrei
}
Listing 29.41: Die Klasse »SpinlockMutex« verhindert das Schlafenlegen beim Warten.
Book listing lst-1047-book.cpp:
// https://godbolt.org/z/W47YTYcEb
#include <atomic>
class SpinlockMutex {
std::atomic_flag flag_;
public:
SpinlockMutex()
: flag_{ATOMIC_FLAG_INIT}
{}
void lock() { // z. B. von lock_guard aufgerufen
while(flag_.test_and_set(std::memory_order_acquire)) // hauptsächlich lesen
{ /* nothing */ }
}
void unlock() {
flag_.clear(std::memory_order_release); // Schreiboperation
}
};
Godbolt Listing lst-1047-godb.cpp, https://godbolt.org/z/W47YTYcEb:
//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/W47YTYcEb
#include <atomic>
class SpinlockMutex {
std::atomic_flag flag_;
public:
SpinlockMutex()
: flag_{ATOMIC_FLAG_INIT}
{}
void lock() { // z. B. von lock_guard aufgerufen
while(flag_.test_and_set(std::memory_order_acquire)) // hauptsächlich lesen
{ /* nothing */ }
}
void unlock() {
flag_.clear(std::memory_order_release); // Schreiboperation
}
};
Listing 29.42: Ihre Koroutine liefert einen »generator« zurück.
Book listing lst-1048-book.cpp:
// https://godbolt.org/z/Gfazq6GE7
#include <generator>
#include <iostream>
#include <vector>
std::generator<int> fib(int n) { // generiert int-Werte
int a = 0, b = 1;
while (--n) {
co_yield b; // macht diese Funktion zu einer Koroutine
auto tmp = a;
a = b;
b += tmp;
}
}
int main() {
for (auto i : fib(10)) std::cout << i << ' ';
std::cout << '\n'; // Ausgabe: 1 1 2 3 5 8 13 21 34 55
}
Godbolt Listing lst-1048-godb.cpp, https://godbolt.org/z/Gfazq6GE7:
//#(compile) c++; compiler:gsnapshot; options:"-std=c++23"; libs:-
// https://godbolt.org/z/Gfazq6GE7
#include <generator>
#include <iostream>
#include <vector>
std::generator<int> fib(int n) { // generiert int-Werte
int a = 0, b = 1;
while (--n) {
co_yield b; // macht diese Funktion zu einer Koroutine
auto tmp = a;
a = b;
b += tmp;
}
}
int main() {
for (auto i : fib(10)) std::cout << i << ' ';
std::cout << '\n'; // Ausgabe: 1 1 2 3 5 8 13 21 34 55
}
Listing 29.43: Ein einfaches Beispiel für einen Koroutinen-Rückgabetyp mit seinem »promise_type«
Book listing lst-1049-book.cpp:
// https://godbolt.org/z/4ed3oWK7q
#include <coroutine>
#include <iostream>
struct Routine { // Koroutinen-Rückgabetyp
struct promise_type; // weiter unten definiert
Routine(auto h) : hdl_(h) {} // Konstruktor
~Routine() { if(hdl_) hdl_.destroy(); } // Destruktor
Routine(const Routine&) = delete; // keine Kopien
Routine(Routine&&) = delete; // keine Verschiebungen
// Schnittstelle für den Aufrufer:
bool more() { // Koroutine fortsetzen
if(!hdl_ || hdl_.done()) return false; // - nichts mehr zu tun
hdl_.resume(); // - blockierender Aufruf
return !hdl_.done(); // - signalisiert fertig oder nicht
}
private:
using handle_type_ = std::coroutine_handle<promise_type>;
handle_type_ hdl_; // zum Steuern der Koroutine
};
struct Routine::promise_type { // notwendiger promise_type
auto get_return_object() { // initialisiert das Handle
return Routine{ handle_type_::from_promise(*this) };
}
auto initial_suspend() { return std::suspend_never{}; } // sofort starten
auto final_suspend() noexcept { return std::suspend_always{}; } // Normalfall
void unhandled_exception() {} // keine Exception-Behandlung
void return_void() {} // Koroutine hat keine Rückgabe
};
Routine counter() { // Rückgabetyp ist unsere Wrapperklasse mit dem promise_type
for (unsigned i = 0;; ++i) {
co_await std::suspend_always{}; // Koroutine pausieren
std::cout << "counter: " << i << std::endl;
}
}
int main() {
Routine routine = counter(); // Koroutine erzeugen und starten
for (int i = 0; i < 3; ++i) {
std::cout << "Hallo main!\n";
routine.more(); // Koroutine fortsetzen
}
}
Godbolt Listing lst-1049-godb.cpp, https://godbolt.org/z/4ed3oWK7q:
//#(compile) c++; compiler:g132; options:"-std=c++20"; libs:-
// https://godbolt.org/z/4ed3oWK7q
#include <coroutine>
#include <iostream>
struct Routine { // Koroutinen-Rückgabetyp
struct promise_type; // weiter unten definiert
Routine(auto h) : hdl_(h) {} // Konstruktor
~Routine() { if(hdl_) hdl_.destroy(); } // Destruktor
Routine(const Routine&) = delete; // keine Kopien
Routine(Routine&&) = delete; // keine Verschiebungen
// Schnittstelle für den Aufrufer:
bool more() { // Koroutine fortsetzen
if(!hdl_ || hdl_.done()) return false; // - nichts mehr zu tun
hdl_.resume(); // - blockierender Aufruf
return !hdl_.done(); // - signalisiert fertig oder nicht
}
private:
using handle_type_ = std::coroutine_handle<promise_type>;
handle_type_ hdl_; // zum Steuern der Koroutine
};
struct Routine::promise_type { // notwendiger promise_type
auto get_return_object() { // initialisiert das Handle
return Routine{ handle_type_::from_promise(*this) };
}
auto initial_suspend() { return std::suspend_never{}; } // sofort starten
auto final_suspend() noexcept { return std::suspend_always{}; } // Normalfall
void unhandled_exception() {} // keine Exception-Behandlung
void return_void() {} // Koroutine hat keine Rückgabe
};
Routine counter() { // Rückgabetyp ist unsere Wrapperklasse mit dem promise_type
for (unsigned i = 0;; ++i) {
co_await std::suspend_always{}; // Koroutine pausieren
std::cout << "counter: " << i << std::endl;
}
}
int main() {
Routine routine = counter(); // Koroutine erzeugen und starten
for (int i = 0; i < 3; ++i) {
std::cout << "Hallo main!\n";
routine.more(); // Koroutine fortsetzen
}
}
GodboltId:veEq4dcET
Book listing lst-1052-book.cpp:
// https://godbolt.org/z/veEq4dcET
struct Tag {
Tag(int a, int b) : Tag{} { // delegiert
if(a==0 || b == 0)
throw 666; // löst Ausnahme aus
}
Tag() {}
};
int main() {
try {
Tag tag{1,2};
} catch(int) { }
}
Godbolt Listing lst-1052-godb.cpp, https://godbolt.org/z/veEq4dcET:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/veEq4dcET
struct Tag {
Tag(int a, int b) : Tag{} { // delegiert
if(a==0 || b == 0)
throw 666; // löst Ausnahme aus
}
Tag() {}
};
int main() {
try {
Tag tag{1,2};
} catch(int) { }
}
GodboltId:Y8KK3nEG3
Book listing lst-1057-book.cpp:
// https://godbolt.org/z/Y8KK3nEG3
void sortData(std::ranges::random_access_range auto &&data) {
std::ranges::sort(data);
}
Godbolt Listing lst-1057-godb.cpp, https://godbolt.org/z/Y8KK3nEG3:
//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Y8KK3nEG3
void sortData(std::ranges::random_access_range auto &&data) {
std::ranges::sort(data);
}