Wie schon zuletzt beschrieben, galt es C++ Software aus einem Nachbarprojekt zu übernehmen. Die dort tätigen Kollegen verwendeten begeistert die Features von C++ 2014. Vor allem der Datentyp „auto“ und die Initialisierung mit geschweiften Klammern hatte es ihnen angetan. Auch setzten sie shared_ptr und unique_ptr ein. Falls diese dann doch mit traditionellen Pointer darunter mischen, startet unter Umständen eine interessante Fehlersuche.
Aber mich interessierte die Art und Weise wie sie lambdas einbauten. Ich suchte nach eckigen Klammer gefolgt von einer geöffneten Klammer und konnte drei Sorten identifizieren:
- lokale Subroutinen (hätte man auch mit #defines machen können)
- Abräumer von von Windows handles (scope guard, geht kaum ohne lambdas)
- zur Initialisierung von static Variablen (das fand ich cool)
lokale Subroutinen
void very_long_function(){
#define MACRO do { \
xyzzy(); \
other_func(); \
}while(0)
....
MACRO;
....
MACRO;
#undef MACRO
}
void very_long_function()
{
auto macro = [&]() {
xyzzy();
other_func();
};
...
macro();
...
macro();
}
Abräumer
Das RAII Prinzip ist hier das Schlagwort. In C++ fordert eine Instanz auf dem Stack eine Resource im Konstruktor an und gibt sie im Destruktor wieder frei.
Allerdings gibt es in gewachsenen Source mit Microsoft API Einschlägen immer die Tendenz Handles außerhalb von Objekten zu verwenden. Diese dann wieder in allen Fehlerfällen freizugeben und das auch nur, wenn sie wirklich angelegt wurden, erfordert ziemliches Geschick und führt vielen Möglichkeiten Fehler zu machen.
Nun gibt es scope_guard. Im Source habe ich zwei Implementierungen entdeckt. Beide arbeiten ähnlich:
// irgendwo in einer Funktion
HBITMAP hBitmap = (HBITMAP)::LoadImage(hInst, MAKEINTRESOURCE(ressourceId),
IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
auto _ = scope::finally([&] { ::DeleteObject(hBitmap); });
// Wann immer dieser Block verlassen wird, wird hBitmap entfern!.
Initialisierung von static Variablen
const CString& CDlBmpReplacer ::GetPathToProIcons()
{
static CString s_sPathToProIcons = []() {
const int verylongNumbertoholdthepath = (1024 * 8);
CHAR buf[verylongNumbertoholdthepath];
DWORD lenOfPath = GetModuleFileName(NULL, buf, verylongNumbertoholdthepath);
assert(lenOfPath > 0); // not long enough
for (; buf[lenOfPath - 1] != '\\' && buf[lenOfPath - 1] != '/'; lenOfPath--)
;
strcpy(buf + lenOfPath, cpcProIconPathRelative);
return CString(buf);
}();
return s_sPathToProIcons;
}