
Vad är Modern C++?
När man pratar om Modern C++, så tänker många direkt på nya språkfunktioner som auto, range-based for, smart pointers, lambdas, constexpr, concepts och mycket mer. Men i grunden handlar Modern C++ om något ännu viktigare: ett nytt sätt att tänka. Ett tankesätt där resurser följer ägarskap, objekt är lokala, och språket hjälper oss att skriva robust, effektiv och underhållbar kod.
Låt oss börja med ett klassiskt exempel från Classic C/C++, där resurshantering var helt upp till programmeraren.
Ett klassiskt C/C++-exempel med läckor
#include <iostream>
#include <cstring>
char* greet(const char* name) {
char* buffer = new char[100];
::strcpy(buffer, "Hello ");
::strcat(buffer, name);
return buffer;
}
int main() {
char* message = greet("Anna");
std::cout << message << "\n";
// Glömt att frigöra minnet!
}
Här har vi ett klassiskt exempel: vi allokerar minne på heapen med new, men glömmer att delete-a det. Resultat: minnesläcka. Och det här är inte ett undantag — det är tyvärr väldigt vanligt i äldre C++-kod.
Samma program, men med Modern C++
#include <iostream>
#include <string>
std::string greet(const std::string& name) { return "Hello " + name; }
int main() {
auto message = greet("Anna");
std::cout << message << "\n";
}
Vad har vi gjort här?
Vi använder std::string
istället för råa char*
.
Vi returnerar ett värde by value, men tack vare Return Value Optimization (RVO) så sker ingen onödig kopiering.
Inga new
, inga delete
, och inga läckor.
Grundprincip: Allokera lokalt
En av de viktigaste principerna i Modern C++ är:
Allokera lokalt, använd stacken — inte heapen.
Detta innebär att man i första hand skapar lokala objekt som har väldefinierad livstid. När ett objekt går ur scope, så anropas dess destruktor automatiskt — och eventuell resurshantering (minne, filhandtag, mutexar etc.) sker deterministiskt. Här är ett exempel som illustrerar det:
#include <iostream>
#include <vector>
#include <memory>
class Logger {
public:
Logger() { std::cout << "Logger started\n"; }
~Logger() { std::cout << "Logger stopped\n"; }
void print(const std::string& msg) {
std::cout << "[LOG] " << msg << "\n";
}
};
void do_work() {
auto log = Logger{}; // lokal variabel
log.print("Processing...");
// automatisk cleanup när funktionen returnerar
}
int main() {
do_work();
}
Kör du detta, ser du följande:
Logger started
[LOG] Processing...
Logger stopped
Inget behov av new eller delete, inget behov av try/catch/finally, inget behov av att oroa sig för att någon glömt att städa upp. C++ fixar det åt dig — så länge du allokerar lokalt.
Reflektion: Varför modernisera?
Det finns flera goda skäl till att använda Modern C++:
Färre buggar.
Mindre manuell minneshantering = färre läckor och use-after-free.
Bättre läsbarhet.
Koden blir mer deklarativ och lättare att följa. "Vad" som händer är tydligare än "hur".
Effektivitet.
Tack vare RVO, move-semantik, och inline-expansion blir koden inte bara säkrare — utan också snabbare.
Starkare typer och bättre kontroll.
Funktioner som auto, constexpr, enum class, concepts m.fl. ger tydligare kontrakt och bättre kompilatorstöd.
Det handlar inte om att lära sig ett nytt språk — det är fortfarande C++. Men det är ett bättre sätt att skriva det på.
Så nästa gång du sitter och skriver ny C++-kod, tänk:
"Kan jag skriva detta med lokala objekt? Behöver jag verkligen heapen? Har standardbiblioteket redan löst detta åt mig?"
Och om svaret är ja, så vet du att du är på väg in i Modern C++-land.
Min katt, C++, föredrar också lokala variabler. Det är enklare att hålla reda på dem när han spinner.