C++ für Fortgeschrittene - ein Kurs unter Mithilfe von chatGPT-4

Dr. Erhard Henkes,  Stand: 10.04.2023

Das KI-System ChatGPT (wohl Version 4 o.ä.) im Rahmen von bing.com habe ich um Beispiele für moderne Sprachfeatures in C++ gebeten. Folgende Ideen kamen dabei heraus:

ChatGPT: Ja, ich kann dir gerne helfen, ein modernes C++-Tutorial zu entwerfen. Hier sind einige Beispiele für moderne C++-Sprachfeatures, die du in deinem Tutorial behandeln könntest:

Automatische Typinferenz mit auto:
Mit auto kann der Compiler den Typ einer Variable automatisch ableiten, basierend auf dem Wert, der ihr zugewiesen wird.
Dies kann den Code lesbarer und weniger fehleranfällig machen.

#include <iostream>
#include <vector>

int main()
{
  std::vector<int> v = {1, 2, 3};
  for (auto i : v)
  {
    std::cout << i << ' ';
  }
  std::cout << '\n';
}


Bereichsbasierte for-Schleifen:
Bereichsbasierte for-Schleifen ermöglichen es, über Container wie std::vector oder std::array zu iterieren, ohne explizit Indizes oder Iteratoren verwenden zu müssen.

#include <iostream>
#include <vector>

int main()
{
  std::vector<int> v = {1, 2, 3};
  for (int i : v)
  {
    std::cout << i << ' ';
  }
  std::cout << '\n';
}

 

Lambda-Ausdrücke:
Lambda-Ausdrücke sind anonyme Funktionen, die direkt im Code definiert werden können.
Sie sind besonders nützlich für kurze Funktionen, die an andere Funktionen wie std::sort oder std::for_each übergeben werden.

#include <algorithm>
#include <iostream>
#include <vector>

int main()
{
  std::vector<int> v = {3, 1, 2};
  std::sort(v.begin(), v.end(), [](int a, int b) { return a < b; });
  for (int i : v)
  {
    std::cout << i << ' ';
 
}
  std::cout << '\n';
}



Einheitliche Initialisierung:
Mit der einheitlichen Initialisierung kannst du Objekte mit geschweiften Klammern initialisieren, unabhängig davon, ob es sich um eingebaute Typen, Container oder benutzerdefinierte Typen handelt.

#include <iostream>
#include <vector>

int main()
{
  int a{1};
  std::vector<int> v{1, 2, 3};
  for (int i : v)
  {
    std::cout << i << ' ';
  }
  std::cout << '\n';
}}




Intelligente Zeiger:
Intelligente Zeiger wie std::unique_ptr und std::shared_ptr ermöglichen eine automatische Speicherverwaltung und vermeiden häufige Fehler wie Speicherlecks oder doppelte Freigaben.



#include <iostream>
#include <memory>

struct Foo
{
  Foo()  { std::cout << "Foo ctor\n"; }
  ~Foo() { std::cout << "Foo dtor\n"; }
};

int main()
{
  std::unique_ptr<Foo> p1(new Foo);
  std::unique_ptr<Foo> p2 = std::make_unique<Foo>();
}



Move Semantik:
Move-Semantik ermöglicht es, Ressourcen von einem Objekt zu einem anderen zu übertragen, anstatt sie zu kopieren. Dies kann die Leistung verbessern und unnötige Kopien vermeiden.



#include <iostream>
#include <utility>
#include <vector>

int main()
{
  std::vector<int> v1 = {1, 2, 3};
  std::vector<int> v2 = std::move(v1);
  for (int i : v2)
  {
    std::cout << i << ' ';
  }
  std::cout << '\n';
}






constexpr:

Mit constexpr kannst du angeben, dass der Wert eines Ausdrucks zur Compile-Zeit berechnet werden kann. Dies kann die Leistung verbessern und ermöglicht die Verwendung von Ausdrücken in Kontexten, in denen zur Compile-Zeit berechnete Werte erforderlich sind.


#include <iostream>

constexpr int factorial(int n)
{
  return n <= 1 ? 1 : (n * factorial(n - 1));
}

int main()
{
  std::cout << factorial(5) << '\n';
}

 


Variadische Templates:

Variadische Templates ermöglichen es dir, Funktionen und Klassen zu definieren, die eine variable Anzahl von Template-Parametern akzeptieren.

 

#include <iostream>

template<typename T>
T adder(T v)
{
  return v;
}

template<typename T, typename... Args>
T adder(T first, Args... args)
{
  return first + adder(args...);
}

int main()
{
  std::cout << adder(1, 2, 3, 4) << '\n';
}




Delegierende Konstruktoren:
Mit delegierenden Konstruktoren kannst du einen Konstruktor von einem anderen Konstruktor derselben Klasse aufrufen.
Dies kann den Code vereinfachen und redundante Initialisierungen vermeiden.

#include <iostream>

struct Foo
{
  int x;
  Foo(int x) : x(x) { std::cout << "Foo ctor\n"; }
  Foo() : Foo(0) {}
};

int main()
{
  Foo f1(1);
  Foo f2;
}


Ein weiteres wichtiges Kapitel in einem modernen C+±Tutorial könnte die Verwendung der Standardbibliothek sein.
Die C+±Standardbibliothek bietet eine Vielzahl von nützlichen Funktionen und Klassen, die viele häufige Aufgaben vereinfachen können: Container, Algorithmen, Stringverarbeitung.