new
a delete
operátory
Jazyk C++ podporuje dynamické přidělování a přidělování objektů pomocí operátorů new
a delete
operátorů. Tyto operátory přidělují paměť pro objekty z fondu označovaného jako volné úložiště (označované také jako halda). Operátor new
volá speciální funkci operator new
a delete
operátor volá speciální funkci operator delete
.
Seznam souborů knihovny v knihovně modulu runtime jazyka C a standardní knihovně jazyka C++ naleznete v tématu Funkce knihovny CRT.
Operátor new
Kompilátor přeloží příkaz, jako je tento, do volání funkce operator new
:
char *pch = new char[BUFFER_SIZE];
Pokud je požadavek pro nulové bajty úložiště, operator new
vrátí ukazatel na jedinečný objekt. To znamená, že opakované volání pro operator new
vrácení různých ukazatelů.
Pokud není dostatek paměti pro požadavek na přidělení, operator new
vyvolá std::bad_alloc
výjimku. Nebo se vrátínullptr
, pokud jste použili formulář new(std::nothrow)
pro umístění nebo pokud jste propojili podporu, která nevyvolá podporuoperator new
. Další informace najdete v tématu Chování selhání přidělení.
Tyto dva obory pro operator new
funkce jsou popsány v následující tabulce.
Rozsah funkcí operator new
Operátor | Obor |
---|---|
::operator new |
Globální |
název třídy ::operator new |
Třída |
První argument operator new
musí být typu size_t
a návratový typ je vždy void*
.
Globální operator new
funkce se volá, když new
se operátor používá k přidělení objektů předdefinovaných typů, objektů typu třídy, které neobsahují uživatelem definované operator new
funkce a pole jakéhokoli typu. Pokud je new
operátor použit k přidělení objektů typu třídy, kde operator new
je definován, je volána tato třída operator new
.
Funkce operator new
definovaná pro třídu je statická členová funkce (která nemůže být virtuální), která skryje globální operator new
funkci pro objekty daného typu třídy. Vezměte v úvahu případ, kdy new
se používá k přidělení a nastavení paměti na danou hodnotu:
#include <malloc.h>
#include <memory.h>
class Blanks
{
public:
Blanks(){}
void *operator new( size_t stAllocateBlock, char chInit );
};
void *Blanks::operator new( size_t stAllocateBlock, char chInit )
{
void *pvTemp = malloc( stAllocateBlock );
if( pvTemp != 0 )
memset( pvTemp, chInit, stAllocateBlock );
return pvTemp;
}
// For discrete objects of type Blanks, the global operator new function
// is hidden. Therefore, the following code allocates an object of type
// Blanks and initializes it to 0xa5
int main()
{
Blanks *a5 = new(0xa5) Blanks;
return a5 != 0;
}
Argument zadaný v závorkách se new
předá Blanks::operator new
jako chInit
argument. Globální operator new
funkce je však skrytá, což způsobuje, že kód, například následující, vygeneruje chybu:
Blanks *SomeBlanks = new Blanks;
Kompilátor podporuje členské pole new
a delete
operátory v deklaraci třídy. Příklad:
class MyClass
{
public:
void * operator new[] (size_t)
{
return 0;
}
void operator delete[] (void*)
{
}
};
int main()
{
MyClass *pMyClass = new MyClass[5];
delete [] pMyClass;
}
Chování selhání přidělení
Funkce new
ve standardní knihovně C++ podporuje chování zadané ve standardu C++ od jazyka C++98. Pokud není dostatek paměti pro požadavek na přidělení, operator new
vyvolá std::bad_alloc
výjimku.
Starší kód C++ vrátil ukazatel null pro neúspěšné přidělení. Pokud máte kód, který očekává nehození verze new
, propojte program s nothrownew.obj
. Soubor nothrownew.obj
nahradí globální operator new
verzí, která se vrátí nullptr
, pokud přidělení selže. operator new
už ho nehodí std::bad_alloc
. Další informace o nothrownew.obj
souborech možností linkeru a dalších souborech možností linkeru najdete v tématu Možnosti propojení.
Kód, který kontroluje výjimky z globálního operator new
prostředí, nemůžete kombinovat s kódem, který kontroluje ukazatele null ve stejné aplikaci. Přesto ale můžete vytvořit místní operator new
třídu, která se chová jinak. Tato možnost znamená, že kompilátor musí ve výchozím nastavení jednat defenzivně a zahrnout kontroly návratu ukazatele null do new
volání. Další informace o způsobu optimalizace těchto kontrol kompilátoru naleznete v tématu /Zc:throwingnew
.
Zpracování nedostatečné paměti
Způsob, jakým testujete neúspěšné přidělení z výrazu new
, závisí na tom, jestli používáte standardní mechanismus výjimky, nebo použijete nullptr
návrat. Standard C++ očekává, že alokátor vyvolá buď std::bad_alloc
nebo třídu odvozenou z std::bad_alloc
. Takovou výjimku můžete zpracovat, jak je znázorněno v této ukázce:
#include <iostream>
#include <new>
using namespace std;
#define BIG_NUMBER 10000000000LL
int main() {
try {
int *pI = new int[BIG_NUMBER];
}
catch (bad_alloc& ex) {
cout << "Caught bad_alloc: " << ex.what() << endl;
return -1;
}
}
Při použití nothrow
formuláře new
můžete otestovat selhání přidělení, jak je znázorněno v této ukázce:
#include <iostream>
#include <new>
using namespace std;
#define BIG_NUMBER 10000000000LL
int main() {
int *pI = new(nothrow) int[BIG_NUMBER];
if ( pI == nullptr ) {
cout << "Insufficient memory" << endl;
return -1;
}
}
Pokud jste použili nothrownew.obj
soubor k nahrazení globálního operator new
souboru, můžete otestovat přidělení paměti, které selhalo, jak je znázorněno tady:
#include <iostream>
#include <new>
using namespace std;
#define BIG_NUMBER 10000000000LL
int main() {
int *pI = new int[BIG_NUMBER];
if ( !pI ) {
cout << "Insufficient memory" << endl;
return -1;
}
}
Můžete zadat obslužnou rutinu pro neúspěšné žádosti o přidělení paměti. Je možné napsat vlastní rutinu obnovení, která takové selhání zpracuje. Může například uvolnit rezervovanou paměť a pak povolit opětovné spuštění přidělení. Další informace najdete na webu _set_new_handler
.
Operátor delete
Paměť, která je dynamicky přidělena pomocí operátoru new
, lze uvolnit pomocí operátoru delete
. Operátor delete volá operator delete
funkci, která uvolní paměť zpět do dostupného fondu. Použití operátoru delete
také způsobí, že se volá destruktor třídy (pokud existuje).
Existují globální funkce a funkce s oborem operator delete
třídy. Pro danou třídu lze definovat pouze jednu operator delete
funkci. Pokud je definována, skryje globální operator delete
funkci. operator delete
Globální funkce se vždy volá pro pole libovolného typu.
Globální operator delete
funkce. Pro globální operator delete
a členské operator delete
funkce existují dvě formy:
void operator delete( void * );
void operator delete( void *, size_t );
Pro danou třídu může existovat pouze jeden z předchozích dvou formulářů. První formulář přebírá jeden argument typu void *
, který obsahuje ukazatel na objekt k uvolnění. Druhý formulář, velikost zrušení přidělení, má dva argumenty: první je ukazatel na blok paměti, který se má uvolnit, a druhý je počet bajtů, které se mají uvolnit. Návratový typ obou formulářů je void
(operator delete
nemůže vrátit hodnotu).
Záměrem druhého formuláře je urychlit hledání správné kategorie velikosti objektu, který se má odstranit. Tyto informace se často neukládají blízko samotného přidělení a pravděpodobně se neukládají do mezipaměti. Druhý formulář je užitečný, pokud operator delete
se funkce ze základní třídy používá k odstranění objektu odvozené třídy.
Funkce operator delete
je statická, takže nemůže být virtuální. Funkce operator delete
dodržuje řízení přístupu, jak je popsáno v části Řízení přístupu člena.
Následující příklad ukazuje uživatelem definované operator new
funkce a operator delete
funkce navržené pro protokolování přidělení a uvolnění paměti:
#include <iostream>
using namespace std;
int fLogMemory = 0; // Perform logging (0=no; nonzero=yes)?
int cBlocksAllocated = 0; // Count of blocks allocated.
// User-defined operator new.
void *operator new( size_t stAllocateBlock ) {
static int fInOpNew = 0; // Guard flag.
if ( fLogMemory && !fInOpNew ) {
fInOpNew = 1;
clog << "Memory block " << ++cBlocksAllocated
<< " allocated for " << stAllocateBlock
<< " bytes\n";
fInOpNew = 0;
}
return malloc( stAllocateBlock );
}
// User-defined operator delete.
void operator delete( void *pvMem ) {
static int fInOpDelete = 0; // Guard flag.
if ( fLogMemory && !fInOpDelete ) {
fInOpDelete = 1;
clog << "Memory block " << cBlocksAllocated--
<< " deallocated\n";
fInOpDelete = 0;
}
free( pvMem );
}
int main( int argc, char *argv[] ) {
fLogMemory = 1; // Turn logging on
if( argc > 1 )
for( int i = 0; i < atoi( argv[1] ); ++i ) {
char *pMem = new char[10];
delete[] pMem;
}
fLogMemory = 0; // Turn logging off.
return cBlocksAllocated;
}
Předchozí kód lze použít ke zjištění "úniku paměti", tj. paměti přidělené v bezplatném úložišti, ale nikdy se neuskutečnily. Aby bylo zjištěno nevracení, globální operátory a delete
operátory jsou znovu definovány tak, new
aby se počítá přidělení a uvolnění paměti.
Kompilátor podporuje členské pole new
a delete
operátory v deklaraci třídy. Příklad:
// spec1_the_operator_delete_function2.cpp
// compile with: /c
class X {
public:
void * operator new[] (size_t) {
return 0;
}
void operator delete[] (void*) {}
};
void f() {
X *pX = new X[5];
delete [] pX;
}