Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Sinds de creatie is C++ een van de meest gebruikte programmeertalen ter wereld geworden. Goed geschreven C++-programma's zijn snel en efficiënt. De taal is flexibeler dan andere talen: het kan werken op de hoogste abstractieniveaus en omlaag op het niveau van het silicium. C++ levert uiterst geoptimaliseerde standaardbibliotheken. Het maakt toegang tot hardwarefuncties op laag niveau mogelijk, om de snelheid te maximaliseren en geheugenvereisten te minimaliseren. C++ kan vrijwel elk soort programma maken: Games, apparaatstuurprogramma's, HPC, cloud, desktop, ingesloten en mobiele apps, en nog veel meer. Zelfs bibliotheken en compilers voor andere programmeertalen worden geschreven in C++.
Een van de oorspronkelijke vereisten voor C++ was achterwaartse compatibiliteit met de C-taal. Als gevolg hiervan heeft C++ altijd C-stijl programmeren toegestaan, met onbewerkte aanwijzers, matrices, null-beëindigde tekenreeksen en andere functies. Ze kunnen goede prestaties mogelijk maken, maar kunnen ook bugs en complexiteit spawnen. De ontwikkeling van C++ heeft de nadruk gelegd op functies die de noodzaak om C-stijl idiomen te gebruiken aanzienlijk verminderen. De oude C-programmeerfaciliteiten zijn er nog steeds wanneer u ze nodig hebt. In moderne C++-code hebt u deze echter minder en minder nodig. Moderne C++-code is eenvoudiger, veiliger, eleganter en nog steeds zo snel als ooit.
De volgende secties bieden een overzicht van de belangrijkste functies van moderne C++. Tenzij anders vermeld, zijn de hier vermelde functies beschikbaar in C++11 en hoger. In de Microsoft C++-compiler kunt u de /std compileroptie instellen om op te geven welke versie van de standaard moet worden gebruikt voor uw project.
Resources en slimme aanwijzers
Een van de belangrijkste klassen bugs in programmeren in C-stijl is het geheugenlek. Lekken worden vaak veroorzaakt door een fout bij het aanroepen van delete voor geheugen dat is toegewezen met new. Modern C++ benadrukt het principe van resourceverwerving bij initialisatie (RAII). Het idee is eenvoudig. Resources (heapgeheugen, bestandsingangen, sockets, enzovoort) moeten eigendom zijn van een object. Dit object maakt of ontvangt de zojuist toegewezen resource in zijn constructor en verwijdert deze in zijn destructor. Het principe van RAII garandeert dat alle resources correct worden teruggezet naar het besturingssysteem wanneer het eigendomsobject buiten het bereik valt.
Ter ondersteuning van eenvoudige acceptatie van RAII-principes biedt de C++ Standaardbibliotheek drie typen slimme aanwijzers: std::unique_ptr, std::shared_ptren std::weak_ptr. Een slimme pointer behandelt de toewijzing en verwijdering van het geheugen waarvan het de eigenaar is. In het volgende voorbeeld ziet u een klasse met een arraylid dat is toegewezen aan de heap in de aanroep naar make_unique(). De aanroepen naar new en delete worden ingekapseld door de unique_ptr klasse. Wanneer een widget object buiten het bereik valt, wordt de unique_ptr destructor aangeroepen en wordt het geheugen vrijgegeven dat voor de matrix is toegewezen.
#include <memory>
class widget
{
private:
std::unique_ptr<int[]> data;
public:
widget(const int size) { data = std::make_unique<int[]>(size); }
void do_something() {}
};
void functionUsingWidget() {
widget w(1000000); // lifetime automatically tied to enclosing scope
// constructs w, including the w.data gadget member
// ...
w.do_something();
// ...
} // automatic destruction and deallocation for w and w.data
Gebruik waar mogelijk een slimme aanwijzer om heapgeheugen te beheren. Als u de new operatoren delete expliciet moet gebruiken, volgt u het principe van RAII. Zie De levensduur van objecten en resourcebeheer (RAII) voor meer informatie.
std::string en std::string_view
C-stijl strings zijn een andere belangrijke bron van bugs. Met behulp van std::string en std::wstring kunt u vrijwel alle fouten elimineren die zijn gekoppeld aan tekenreeksen in C-stijl. U krijgt ook het voordeel van lidfuncties voor het zoeken, toevoegen, voorbereiden, enzovoort. Beide zijn sterk geoptimaliseerd voor snelheid. Wanneer u een tekenreeks doorgeeft aan een functie waarvoor alleen-lezentoegang is vereist, kunt u in C++17 een nog groter prestatievoordeel gebruiken std::string_view .
std::vector en andere containers van de standaardbibliotheek
De standaardbibliotheekcontainers volgen allemaal het principe van RAII. Ze bieden iterators voor veilige iteratie van elementen. En ze zijn sterk geoptimaliseerd voor prestaties en zijn grondig getest op juistheid. Door deze containers te gebruiken, elimineert u het potentieel voor bugs of inefficiënties die kunnen worden geïntroduceerd in aangepaste gegevensstructuren. Gebruik in plaats van onbewerkte matrices vector als een sequentiële container in C++.
vector<string> apples;
apples.push_back("Granny Smith");
Gebruik map (niet unordered_map) als de standaard associatieve container. Gebruik set, multimapen multiset voor degenereren en meerdere gevallen.
map<string, string> apple_color;
// ...
apple_color["Granny Smith"] = "Green";
Wanneer prestatieoptimalisatie nodig is, kunt u overwegen het volgende te gebruiken:
- Niet-geordende associatieve containers zoals
unordered_map. Deze hebben lagere overhead per element en een constante zoekactie, maar ze kunnen moeilijker correct en efficiënt worden gebruikt. -
vectorGesorteerd. Zie Algoritmen voor meer informatie.
Gebruik geen C-stijl arrays. Voor oudere API's die directe toegang tot de gegevens nodig hebben, gebruik toegangsmethoden zoals f(vec.data(), vec.size());. Zie C++ Standard Library Containers voor meer informatie over containers.
Standaardbibliotheekalgoritmen
Voordat u ervan uitgaat dat u een aangepast algoritme voor uw programma moet schrijven, moet u eerst de C++ Standard Library-algoritmen controleren. De standaardbibliotheek bevat een steeds groter assortiment algoritmen voor veel algemene bewerkingen, zoals zoeken, sorteren, filteren en randomiseren. De wiskundige bibliotheek is uitgebreid. In C++17 en hoger worden parallelle versies van veel algoritmen geleverd.
Hier volgen enkele belangrijke voorbeelden:
-
for_each, het standaardalgoritme voor doorkruising (samen met op bereik gebaseerdeforlussen). -
transform, voor niet-in-place wijziging van containerelementen -
find_if, het standaardzoekalgoritmen. -
sort,lower_bounden de andere standaard sorteer- en zoekalgoritmen.
Als u een comparator wilt schrijven, gebruikt u strikt < en gebruikt u de benoemde lambdas wanneer u dat kunt.
auto comp = [](const widget& w1, const widget& w2)
{ return w1.weight() < w2.weight(); }
sort( v.begin(), v.end(), comp );
auto i = lower_bound( v.begin(), v.end(), widget{0}, comp );
auto in plaats van expliciete typenamen
C++11 heeft het auto trefwoord geïntroduceerd voor gebruik in variabelen, functies en sjabloondeclaraties.
auto vertelt de compiler het type van het object te afleiden, zodat u het niet expliciet hoeft te typen.
auto is vooral handig wanneer het afgeleid type een geneste sjabloon is:
map<int,list<string>>::iterator i = m.begin(); // C-style
auto i = m.begin(); // modern C++
Op bereik gebaseerde for lussen
Iteratie in C-stijl voor matrices en containers is gevoelig voor indexeringsfouten en is ook vervelend om te typen. Als u deze fouten wilt elimineren en uw code beter leesbaar wilt maken, gebruikt u bereik-gebaseerde for lussen met zowel "Standard Library" containers als onbewerkte arrays. Zie voor meer informatie de op bereik gebaseerde for instructie.
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v {1,2,3};
// C-style
for(int i = 0; i < v.size(); ++i)
{
std::cout << v[i];
}
// Modern C++:
for(auto& num : v)
{
std::cout << num;
}
}
constexpr expressies in plaats van macro's
Macro's in C en C++ zijn tokens die vóór de compilatie door de preprocessor worden verwerkt. Elk exemplaar van een macrotoken wordt vervangen door de gedefinieerde waarde of expressie voordat het bestand wordt gecompileerd. Macro's worden vaak gebruikt in het programmeren in C-stijl om compilatieconstante waarden te definiëren. Macro's zijn echter foutgevoelig en moeilijk om fouten op te sporen. In moderne C++moet u de voorkeur geven aan constexpr variabelen voor compileertijdconstanten:
#define SIZE 10 // C-style
constexpr int size = 10; // modern C++
Uniform initialisatie
In moderne C++ kunt u accolade-initialisatie gebruiken voor elk type. Deze vorm van initialisatie is vooral handig bij het initialiseren van matrices, vectoren of andere containers. In het volgende voorbeeld v2 wordt geïnitialiseerd met drie exemplaren van S.
v3 wordt geïnitialiseerd met drie exemplaren van S, die zelf worden geïnitialiseerd met behulp van accolades. De compiler bepaalt het type van elk element op basis van het gedeclareerde type v3.
#include <vector>
struct S
{
std::string name;
float num;
S(std::string s, float f) : name(s), num(f) {}
};
int main()
{
// C-style initialization
std::vector<S> v;
S s1("Norah", 2.7);
S s2("Frank", 3.5);
S s3("Jeri", 85.9);
v.push_back(s1);
v.push_back(s2);
v.push_back(s3);
// Modern C++:
std::vector<S> v2 {s1, s2, s3};
// or...
std::vector<S> v3{ {"Norah", 2.7}, {"Frank", 3.5}, {"Jeri", 85.9} };
}
Zie accolade-initialisatie voor meer informatie.
Semantiek verplaatsen
Modern C++ biedt verplaatsingssemantiek, waardoor onnodige geheugenkopieën kunnen worden geëlimineerd. In eerdere versies van de taal waren kopieën onvermijdelijk in bepaalde situaties. Met een verplaatsingsbewerking wordt het eigendom van een resource van het ene naar het andere object overgedragen zonder een kopie te maken. Sommige klassen zijn eigenaar van resources, zoals heap-geheugen, bestandsingangen, enzovoort. Wanneer u een klasse implementeert die eigenaar is van een resource, kunt u een verplaatsingsconstructor en verplaatsingstoewijzingsoperator voor deze klasse definiëren. De compiler kiest deze speciale leden tijdens overbelastingsresolutie in situaties waarin een kopie niet nodig is. De containertypen van de Standaardbibliotheek roepen de verplaatsingsconstructor voor objecten aan als er een is gedefinieerd. Zie Move Constructors and Move Assignment Operators (C++) voor meer informatie.
Lambda-expressies
In programmeren in C-stijl kan een functie worden doorgegeven aan een andere functie met behulp van een functiepointer. Functieaanwijzers zijn onhandig om te onderhouden en te begrijpen. De functie waarnaar ze verwijzen, kan elders in de broncode worden gedefinieerd, ver weg van het punt waarop deze wordt aangeroepen. Ze zijn ook niet typeveilig. Modern C++ biedt functieobjecten, klassen die de operator() operator overschrijven, zodat ze kunnen worden aangeroepen als een functie. De handigste manier om functieobjecten te maken, is met inline lambda-expressies. In het volgende voorbeeld ziet u hoe u een lambda-expressie gebruikt om een functieobject door te geven, dat de find_if functie op elk element in de vector wordt aangeroepen:
std::vector<int> v {1,2,3,4,5};
int x = 2;
int y = 4;
auto result = find_if(begin(v), end(v), [=](int i) { return i > x && i < y; });
De lambda-expressie [=](int i) { return i > x && i < y; } kan worden gelezen als 'functie die één argument van het type int gebruikt en een Booleaanse waarde retourneert die aangeeft of het argument groter is dan x en kleiner is dan y.' U ziet dat de variabelen x en y vanuit de omringende context kunnen worden gebruikt in de lambda. De [=] specificeert dat deze variabelen worden vastgelegd op waarde; met andere woorden, de lambda-expressie heeft zijn eigen kopieën van deze waarden.
Uitzonderingen
Modern C++ benadrukt uitzonderingen, geen foutcodes, als de beste manier om foutvoorwaarden te rapporteren en af te handelen. Voor meer informatie, zie moderne C++ best practices voor uitzonderingen en foutafhandeling.
std::atomic
Gebruik de C++-standaardbibliotheekstruct std::atomic en gerelateerde typen voor communicatiemechanismen tussen threads.
std::variant (C++17)
Unions worden vaak gebruikt in C-stijl programmeren om geheugen te besparen door leden van verschillende typen in staat te stellen dezelfde geheugenlocatie te bezetten. Unions zijn echter niet typeveilig en vatbaar voor programmeerfouten. C++17 introduceert de std::variant klasse als een robuuster en veilig alternatief voor vakbonden. De std::visit functie kan op een typeveilige manier worden gebruikt voor toegang tot de leden van een variant type.
Zie ook
Naslaginformatie over C++-taal
Lambda-expressies
C++ Standaardbibliotheek
Microsoft C/C++-taalconformiteit