C++
Minneshantering
Sök…
Syntax
- : :( opt ) new ( expression-list ) ( opt ) new-type-id new-initializer ( opt )
- : :( opt ) new ( expression-list ) ( opt ) ( type-id ) new-initializer ( opt )
- : :( opt ) radera cast-expression
- : :( opt ) radera [] cast-expression
- std :: unique_ptr < type-id > var_name (ny typ-id ( opt )); // C ++ 11
- std :: shared_ptr < type-id > var_name (ny typ-id ( opt )); // C ++ 11
- std :: shared_ptr < type-id > var_name = std :: make_shared < type-id > ( opt ); // C ++ 11
- std :: unique_ptr < type-id > var_name = std :: make_unique < type-id > ( opt ); // C ++ 14
Anmärkningar
En ledande ::
tvingar den nya eller radera operatören att letas upp i global omfattning och åsidosätter eventuella överbelastade klassspecifika nya eller radera operatörer.
De valfria argumenten som följer det new
nyckelordet används vanligtvis för att ringa placeringar nya , men kan också användas för att skicka ytterligare information till allokeraren, till exempel en tagg som begär att minnet ska allokeras från en vald pool.
Den tilldelade typen anges vanligtvis uttryckligen, t.ex. new Foo
, men kan också skrivas som auto
(sedan C ++ 11) eller decltype(auto)
(sedan C ++ 14) för att härleda den från initialiseraren.
Initialisering av det tilldelade objektet sker enligt samma regler som initialisering av lokala variabler. Speciellt kommer objektet att initialiseras om initialiseraren inte utelämnas, och när dynamisk allokering av en skalartyp eller en grupp skalartyp finns det ingen garanti för att minnet kommer att nollställas.
Ett arrayobjekt skapat av ett nytt uttryck måste förstöras med delete[]
, oavsett om det nya uttrycket har skrivits med []
eller inte. Till exempel:
using IA = int[4];
int* pIA = new IA;
delete[] pIA; // right
// delete pIA; // wrong
Stack
Bunten är ett litet minneområde i vilket tillfälliga värden placeras under körning. Tilldelning av data i stacken är mycket snabbt jämfört med tilldelning av heap, eftersom allt minne har tilldelats för detta ändamål.
int main() {
int a = 0; //Stored on the stack
return a;
}
Bunken namnges eftersom kedjor med funktionssamtal kommer att ha sitt tillfälliga minne "staplat" ovanpå varandra, var och en använder en separat liten del av minnet.
float bar() {
//f will be placed on the stack after anything else
float f = 2;
return f;
}
double foo() {
//d will be placed just after anything within main()
double d = bar();
return d;
}
int main() {
//The stack has no user variables stored in it until foo() is called
return (int)foo();
}
Data lagrade i stacken är bara giltiga så länge som omfattningen som tilldelade variabeln fortfarande är aktiv.
int* pA = nullptr;
void foo() {
int b = *pA;
pA = &b;
}
int main() {
int a = 5;
pA = &a;
foo();
//Undefined behavior, the value pointed to by pA is no longer in scope
a = *pA;
}
Gratis lagring (hög, dynamisk tilldelning ...)
Termen "heap" är ett allmänt beräkningsuttryck som betyder ett minneområde från vilket delar kan allokeras och omfördelas oberoende av minnet som tillhandahålls av stapeln .
I C++
hänvisar standarden till detta område som Free Store som anses vara en mer exakt term.
Områden med minne som tilldelats från Free Store kan leva längre än det ursprungliga räckvidden som det tilldelades. Data som är för stora för att lagras på bunten kan också tilldelas från Free Store .
Rått minne kan allokeras och fördelas med de nya och ta bort nyckelord.
float *foo = nullptr;
{
*foo = new float; // Allocates memory for a float
float bar; // Stack allocated
} // End lifetime of bar, while foo still alive
delete foo; // Deletes the memory for the float at pF, invalidating the pointer
foo = nullptr; // Setting the pointer to nullptr after delete is often considered good practice
Det är också möjligt att tilldela matriser med fast storlek med nya och ta bort , med en något annan syntax. Arrayallokering är inte kompatibel med icke-arrayallokering, och blandning av de två leder till hög korruption. Tilldelning av en matris tilldelar också minne för att spåra storleken på matrisen för senare radering på ett implementeringsdefinerat sätt.
// Allocates memory for an array of 256 ints
int *foo = new int[256];
// Deletes an array of 256 ints at foo
delete[] foo;
När man använder nytt och raderar istället malloc och free kommer konstruktören och destruktorn att köras (liknar stackbaserade objekt). Det är därför nya och radera föredras framför malloc och gratis .
struct ComplexType {
int a = 0;
ComplexType() { std::cout << "Ctor" << std::endl; }
~ComplexType() { std::cout << "Dtor" << std::endl; }
};
// Allocates memory for a ComplexType, and calls its constructor
ComplexType *foo = new ComplexType();
//Calls the destructor for ComplexType() and deletes memory for a Complextype at pC
delete foo;
Från C ++ 11 rekommenderas användning av smarta pekare för att indikera ägande.
C ++ 14 lade till std::make_unique
till STL, ändra rekommendationen för att gynna std::make_unique
eller std::make_shared
istället för att använda naken ny och ta bort .
Placering ny
Det finns situationer när vi inte vill lita på Free Store för att tilldela minne och vi vill använda anpassade minnesallokeringar med hjälp av new
.
I dessa situationer kan vi använda Placement New
, där vi kan säga den "nya" operatören att tilldela minne från en fördelad minnesplats
Till exempel
int a4byteInteger;
char *a4byteChar = new (&a4byteInteger) char[4];
I detta exempel är minnet som pekas av a4byteChar
4 byte allokerat till "stack" via a4byteInteger
.
Fördelen med denna typ av minnesallokering är det faktum att programmerare kontrollerar allokeringen. I exemplet ovan, eftersom a4byteInteger
allokeras på stacken, behöver vi inte ringa ett uttryckligt samtal för att "radera a4byteChar".
Samma beteende kan också uppnås för dynamiskt tilldelat minne. Till exempel
int *a8byteDynamicInteger = new int[2];
char *a8byteChar = new (a8byteDynamicInteger) char[8];
I detta fall kommer minnespekaren från a8byteChar
att hänvisa till dynamiskt minne tilldelat av a8byteDynamicInteger
. I det här fallet måste vi dock uttryckligen ringa delete a8byteDynamicInteger
att släppa minnet
Ett annat exempel för C ++ Class
struct ComplexType {
int a;
ComplexType() : a(0) {}
~ComplexType() {}
};
int main() {
char* dynArray = new char[256];
//Calls ComplexType's constructor to initialize memory as a ComplexType
new((void*)dynArray) ComplexType();
//Clean up memory once we're done
reinterpret_cast<ComplexType*>(dynArray)->~ComplexType();
delete[] dynArray;
//Stack memory can also be used with placement new
alignas(ComplexType) char localArray[256]; //alignas() available since C++11
new((void*)localArray) ComplexType();
//Only need to call the destructor for stack memory
reinterpret_cast<ComplexType*>(localArray)->~ComplexType();
return 0;
}