Projektstruktur
mein-projekt/
├─ CMakeLists.txt
├─ src/
│ ├─ main.cpp
│ ├─ rechner.cpp
│ └─ rechner.hpp
├─ tests/
│ └─ test_rechner.cpp
└─ build/ (erzeugt, nicht ins Repository)CMake: das Standard-Buildsystem
cmake_minimum_required(VERSION 3.20)
project(MeinProjekt LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_library(rechner src/rechner.cpp)
target_include_directories(rechner PUBLIC src)
add_executable(programm src/main.cpp)
target_link_libraries(programm PRIVATE rechner)
target_compile_options(programm PRIVATE -Wall -Wextra -Wpedantic)cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build
./build/programm
ctest --test-dir build # Tests ausführenAbhängigkeiten holst du mit vcpkg, Conan oder CMakes FetchContent.
Header und Quelle
// rechner.hpp
#pragma once
int addiere(int a, int b);
// rechner.cpp
#include "rechner.hpp"
int addiere(int a, int b) { return a + b; }#pragma once (oder Include-Guards) verhindert doppeltes Einbinden. Templates und inline-Funktionen stehen komplett im Header.
Tests
Das Mini-Prinzip ohne Bibliothek:
#include <iostream>
#include <string>
#include <cmath>
int fehler = 0;
#define PRUEFE(bedingung) do { \
if (!(bedingung)) { ++fehler; std::cout << "FEHLER Zeile " << __LINE__ << ": " #bedingung "\n"; } \
else std::cout << "ok: " #bedingung "\n"; } while (0)
bool istPalindrom(const std::string& s) {
std::string t;
for (unsigned char c : s) if (std::isalnum(c)) t += static_cast<char>(std::tolower(c));
return std::equal(t.begin(), t.begin() + t.size() / 2, t.rbegin());
}
int main() {
PRUEFE(istPalindrom("Anna"));
PRUEFE(istPalindrom("Ein Esel lese nie"));
PRUEFE(!istPalindrom("Hallo"));
PRUEFE(istPalindrom(""));
PRUEFE(std::abs(0.1 + 0.2 - 0.3) < 1e-9);
std::cout << fehler << " Fehler\n";
return fehler;
}ok: istPalindrom("Anna")
ok: istPalindrom("Ein Esel lese nie")
ok: !istPalindrom("Hallo")
ok: istPalindrom("")
ok: std::abs(0.1 + 0.2 - 0.3) < 1e-9
0 FehlerFür echte Projekte nimm ein Framework: Catch2, GoogleTest oder doctest.
TEST_CASE("addiere") {
REQUIRE(addiere(2, 3) == 5);
REQUIRE(addiere(-1, 1) == 0);
}Werkzeuge
| Werkzeug | Zweck |
|---|---|
-Wall -Wextra -Wpedantic -Wconversion -Wshadow | Warnungen |
-fsanitize=address,undefined,thread | Laufzeitprüfung |
| clang-tidy | statische Analyse, Modernisierungsvorschläge |
| clang-format | einheitliche Formatierung |
| cppcheck | weitere Analyse |
| Valgrind, gdb, lldb | Speicherfehler, Debugger |
| Compiler Explorer (godbolt.org) | Assembler-Ausgabe ansehen |
| Profiler (perf, gprof) | Leistung messen |
Die C++ Core Guidelines (Auswahl)
- Ressourcen besitzt ein Objekt (RAII). Kein rohes
new/delete. - Bevorzuge Werte und Standardcontainer (
vector,string) vor Zeigern. - Rule of Zero: Keine selbst geschriebenen Spezialfunktionen, wenn nicht nötig.
- `const` überall, wo möglich; Parameter als
const&oder Wert. - `override`,
[[nodiscard]],explicitfür Konstruktoren mit einem Parameter. - Algorithmen und Ranges statt handgeschriebener Schleifen.
- Keine Makros für Konstanten und Funktionen;
constexpr,inline, Templates. - Typsichere Auswahl:
enum class,std::variant,std::optional. - Aussagekräftige Namen, kleine Funktionen, klare Zuständigkeiten.
- Fehler früh und laut:
assert, Ausnahmen,static_assert.
Typische Anfängerfallen
| Falle | Lösung |
|---|---|
using namespace std; im Header | vermeiden, std:: schreiben |
| Referenz/Zeiger auf lokale Variable zurückgeben | Wert zurückgeben |
Vergleich von vorzeichenbehafteten mit size_t | std::ssize oder passende Typen |
Iteratoren nach push_back weiterbenutzen | neu holen |
| Basisklasse ohne virtuellen Destruktor | virtual ~Basis() = default; |
Integer-Division: 1 / 2 ist 0 | 1.0 / 2 |
std::map::operator[] legt Einträge an | find/contains |
| Uninitialisierte lokale Variablen | immer mit {} initialisieren |
| Daten werden im Header definiert (mehrfach) | inline/constexpr oder .cpp |
Wie geht es weiter?
- Bücher: "A Tour of C++" (Stroustrup, kompakt), "Effective Modern C++" (Meyers), "C++ Core Guidelines" (frei online)
- Referenz: cppreference.com
- Üben: Exercism, Advent of Code, eigene Spiele mit SDL oder SFML, Qt für Oberflächen
- Spezialgebiete: Spiele (Unreal Engine), Eingebettetes (Arduino, ESP32), Systeme, Hochleistungsrechnen
Merke
- CMake baut Projekte; Header (
.hpp) deklarieren,.cppsetzen um - Tests mit Catch2 oder GoogleTest, Warnungen und Sanitizer immer an
- Core Guidelines: RAII, Rule of Zero,
const, Standardcontainer, keine Makros - clang-tidy und clang-format sichern Qualität
- Moderne Sprachmittel (
enum class, Smart Pointer, Ranges) machen C++ sicher und lesbar
Aufgabe
Lege ein CMake-Projekt mit einer Bibliothek (rechner) und einem Test an, schalte Warnungen und den AddressSanitizer an.