C++ Grundlagen: Systemprogrammierung und Performance – ein Einstieg

C++ ist eine der mächtigsten Programmiersprachen überhaupt – und eine der anspruchsvollsten. Wer C++ beherrscht, versteht Computer auf einer tiefen Ebene: Speicherverwaltung, Hardware-Nähe, maximale Performance. Kein Wunder, dass C++ in Spieleentwicklung, Betriebssystemen, eingebetteten Systemen und der Finanzbranche allgegenwärtig ist. Dieser Artikel führt dich durch die wichtigsten Grundlagen und zeigt dir, warum sich der Einstieg in C++ lohnt.

Geschichte und Einsatzgebiete von C++

C++ wurde in den frühen 1980er Jahren von Bjarne Stroustrup als Erweiterung von C entwickelt – ursprünglich unter dem Namen „C with Classes". Das Ziel: objektorientierte Programmierung mit der rohen Performance von C zu verbinden. Seitdem hat sich C++ enorm weiterentwickelt und ist mit C++11, C++14, C++17, C++20 und C++23 deutlich moderner geworden.

Heute findest du C++ überall, wo es auf Performance ankommt:

Kompilieren mit g++ und clang

C++ ist eine kompilierte Sprache – dein Quellcode wird direkt in Maschinencode übersetzt. Die zwei wichtigsten Compiler sind g++ (GNU Compiler Collection) und clang++ (LLVM-basiert). Beide sind kostenlos und auf allen Plattformen verfügbar.

# Einfache Kompilierung
g++ -std=c++20 -O2 -o meinprogramm main.cpp

# Mit Warnungen (empfohlen!)
g++ -std=c++20 -Wall -Wextra -o meinprogramm main.cpp

# Mit clang
clang++ -std=c++20 -O2 -o meinprogramm main.cpp

Das Flag -std=c++20 aktiviert den C++20-Standard. -O2 aktiviert Optimierungen. -Wall -Wextra zeigt alle wichtigen Warnungen – aktiviere diese immer, sie helfen dir, Fehler früh zu finden.

Ein minimales C++-Programm sieht so aus:

#include <iostream>

int main() {
    std::cout << "Hallo, Welt!" << std::endl;
    return 0;
}

Variablen, Pointer und Referenzen

C++ unterscheidet klar zwischen Werten, Pointern und Referenzen – ein zentrales Konzept, das Einsteiger oft verwirrt.

int x = 42;          // Wert
int* ptr = &x;       // Pointer auf x (speichert Adresse)
int& ref = x;        // Referenz auf x (Alias)

*ptr = 100;          // Wert über Pointer ändern
ref = 200;           // Wert über Referenz ändern (wie x = 200)

std::cout << x;      // 200

Pointer speichern Speicheradressen und können nullptr sein. Referenzen sind Aliase – sie müssen beim Erstellen initialisiert werden und können nicht auf ein anderes Objekt zeigen. Für neue Projekte bevorzuge Referenzen gegenüber raw Pointern – sie sind sicherer und lesbarer.

Speicherverwaltung: Stack vs. Heap

In C++ bist du selbst für die Speicherverwaltung verantwortlich – das ist Fluch und Segen zugleich. Verstehst du den Unterschied zwischen Stack und Heap, vermeidest du die meisten Fehler.

Stack

Lokale Variablen leben auf dem Stack. Der Speicher wird automatisch freigegeben, wenn der Scope endet – schnell und sicher:

void beispiel() {
    int x = 10; // Stack-Speicher
    // x wird automatisch freigegeben wenn Funktion endet
}

Heap und Smart Pointers

Dynamischer Speicher wird mit new auf dem Heap alloziert und muss mit delete freigegeben werden – vergisst du das, entsteht ein Memory Leak. In modernem C++ verwendest du stattdessen Smart Pointers:

#include <memory>

// unique_ptr: exklusiver Besitz, automatische Freigabe
auto ptr = std::make_unique<int>(42);
std::cout << *ptr; // 42
// kein delete nötig!

// shared_ptr: geteilter Besitz (Referenzzählung)
auto shared = std::make_shared<std::string>("Hallo");
auto kopia = shared; // beide zeigen auf denselben String

Die Regel in modernem C++: Verwende niemals raw new/delete – nutze std::make_unique und std::make_shared. Das eliminiert ganze Klassen von Bugs (Memory Leaks, dangling pointers, double free).

Klassen und OOP in C++

C++ unterstützt vollständige Objektorientierung mit Klassen, Vererbung und virtuellen Methoden:

class Fahrzeug {
public:
    Fahrzeug(std::string name, int ps)
        : name_(std::move(name)), ps_(ps) {}

    virtual std::string beschreibung() const {
        return name_ + " mit " + std::to_string(ps_) + " PS";
    }

    virtual ~Fahrzeug() = default; // Wichtig bei Vererbung!

private:
    std::string name_;
    int ps_;
};

class Elektroauto : public Fahrzeug {
public:
    Elektroauto(std::string name, int ps, int reichweite)
        : Fahrzeug(std::move(name), ps), reichweite_(reichweite) {}

    std::string beschreibung() const override {
        return Fahrzeug::beschreibung()
               + ", Reichweite: " + std::to_string(reichweite_) + " km";
    }

private:
    int reichweite_;
};

Wichtig: In C++ müssen Destruktoren in Basisklassen virtual sein, wenn du mit Polymorphismus arbeitest – sonst wird beim Löschen eines Objekts über einen Basisklassen-Pointer der falsche Destruktor aufgerufen.

Die Standard Template Library (STL)

Die STL ist Javas Collections-Framework für C++ – und deutlich mächtiger. Die wichtigsten Container:

#include <vector>
#include <map>
#include <string>
#include <algorithm>

// vector: dynamisches Array
std::vector<int> zahlen = {3, 1, 4, 1, 5, 9};
zahlen.push_back(2);
std::sort(zahlen.begin(), zahlen.end());

// map: sortierte Schlüssel-Wert-Paare
std::map<std::string, int> punkte;
punkte["Alice"] = 95;
punkte["Bob"] = 87;

// Iteration mit range-for (C++11)
for (const auto& [name, wert] : punkte) {
    std::cout << name << ": " << wert << "\n";
}

Weitere wichtige Container: std::array (feste Größe), std::unordered_map (Hash-Map, schneller als map), std::set, std::deque. Die <algorithm>-Bibliothek bietet über 100 Algorithmen: std::sort, std::find, std::transform, std::accumulate und viele mehr.

Modernes C++: C++11 bis C++20

C++ hat sich in den letzten Jahren stark modernisiert. Hier die wichtigsten Neuerungen:

auto und Typinferenz

auto x = 3.14;                          // double
auto it = zahlen.begin();               // Iterator-Typ automatisch
auto lambda = [](int a, int b) { return a + b; };

Move Semantics (C++11)

Move Semantics erlauben es, Ressourcen effizient zu übertragen statt zu kopieren – ein riesiger Performance-Gewinn bei großen Objekten wie Strings oder Vektoren:

std::vector<int> a = {1, 2, 3, 4, 5};
std::vector<int> b = std::move(a); // kein Kopieren!
// a ist jetzt leer, b hat die Daten

Concepts (C++20)

Concepts erlauben lesbare Constraints für Template-Parameter – Code-Fehler werden verständlicher:

template<std::integral T>
T verdopple(T x) { return x * 2; }

Häufige Fallstricke: Undefined Behavior

Undefined Behavior (UB) ist das gefährlichste Konzept in C++. Wenn dein Code UB auslöst, darf der Compiler buchstäblich alles damit machen – das Programm kann abstürzen, falsche Ergebnisse liefern oder scheinbar funktionieren. Häufige UB-Quellen:

Nutze Tools wie AddressSanitizer (-fsanitize=address) und UBSan (-fsanitize=undefined) während der Entwicklung – sie finden solche Fehler zuverlässig.

Build-Systeme: CMake

CMake ist der Standard für C++-Projekte. Es generiert Makefiles oder Projektdateien für IDEs und verwaltet Abhängigkeiten. Ein minimales CMakeLists.txt:

cmake_minimum_required(VERSION 3.20)
project(MeinProjekt)

set(CMAKE_CXX_STANDARD 20)

add_executable(meinprogramm main.cpp)
# Build
mkdir build && cd build
cmake ..
cmake --build .

Für Versionskontrolle deines C++-Projekts ist Git unverzichtbar. Für containerisierte Build-Umgebungen lohnt sich ein Blick auf Docker.

C++ vs. Rust vs. Java – wann welche Sprache?

C++ ist die richtige Wahl, wenn du maximale Performance benötigst, bestehende C++-Codebases pflegst oder in Bereichen wie Spieleentwicklung, Embedded oder Hochfrequenzhandel arbeitest. Rust bietet ähnliche Performance mit strikteren Speichersicherheits-Garantien zur Compile-Zeit – ideal für neue System-Software ohne Legacy-Anforderungen. Java und die JVM-Sprachen sind besser für Enterprise-Backend-Entwicklung, wo Entwicklerproduktivität wichtiger ist als rohe Geschwindigkeit.

Häufige Fragen

Ist C++ für Anfänger geeignet?

C++ hat eine steile Lernkurve – besonders Pointer und Speicherverwaltung fordern Geduld. Wenn du bereits eine andere Sprache kennst (z.B. Python oder Java), fällt der Einstieg leichter. Starte mit modernem C++20 und ignoriere zunächst Legacy-Features – der Code wird deutlich sauberer und verständlicher.

Soll ich C vor C++ lernen?

Nicht zwingend. Modernes C++ ist kein „C mit Klassen" mehr – es hat eigene Idiome und Best Practices. C zu lernen schadet nicht, ist aber keine Voraussetzung. Starte direkt mit C++20 und nutze die STL, Smart Pointers und Ranges von Anfang an.

Was ist der Unterschied zwischen struct und class in C++?

In C++ sind struct und class fast identisch. Der einzige Unterschied: Mitglieder eines struct sind standardmäßig public, bei class standardmäßig private. Konvention: Verwende struct für einfache Daten-Aggregate ohne Logik, class für Objekte mit Verhalten.

Wie vermeide ich Memory Leaks in C++?

Nutze konsequent Smart Pointers (std::unique_ptr, std::shared_ptr) und vermeide raw new/delete. Das RAII-Prinzip (Resource Acquisition Is Initialization) sorgt dafür, dass Ressourcen automatisch freigegeben werden. Tools wie Valgrind oder AddressSanitizer helfen, bestehende Leaks zu finden.

Welche IDE empfiehlst du für C++?

CLion (JetBrains, kostenpflichtig) bietet die beste C++-Unterstützung. Kostenlose Alternativen: VS Code mit der C/C++-Extension von Microsoft oder Qt Creator. Für den Einstieg reicht VS Code völlig aus.