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 newa 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_ta 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 newmůž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;
}