Bagikan melalui


operator new dan delete

C++ mendukung alokasi dinamis dan alokasi objek menggunakan new operator dan delete . Operator ini mengalokasikan memori untuk objek dari kumpulan yang disebut toko gratis (juga dikenal sebagai tumpukan). Operator new memanggil fungsi operator newkhusus , dan delete operator memanggil fungsi operator deletekhusus .

Untuk daftar file pustaka di Pustaka Runtime C dan Pustaka Standar C++, lihat Fitur Pustaka CRT.

Operator new

Pengkompilasi menerjemahkan pernyataan seperti ini ke dalam panggilan ke fungsi operator new:

char *pch = new char[BUFFER_SIZE];

Jika permintaan adalah untuk nol byte penyimpanan, operator new mengembalikan pointer ke objek yang berbeda. Artinya, panggilan berulang untuk operator new mengembalikan pointer yang berbeda.

Jika tidak ada cukup memori untuk permintaan alokasi, operator new berikan std::bad_alloc pengecualian. Atau, ini mengembalikan nullptr jika Anda telah menggunakan formulir new(std::nothrow)penempatan , atau jika Anda telah menautkan dalam dukungan non-throwingoperator new. Untuk informasi selengkapnya, lihat Perilaku kegagalan alokasi.

Dua cakupan untuk operator new fungsi dijelaskan dalam tabel berikut.

Cakupan untuk operator new fungsi

Operator Scope
::operator new Global
nama kelas::operator new Kelas

Argumen pertama harus operator new berjenis size_t, dan jenis pengembalian selalu void*.

Fungsi global operator new dipanggil ketika new operator digunakan untuk mengalokasikan objek jenis bawaan, objek jenis kelas yang tidak berisi fungsi yang ditentukan operator new pengguna, dan array dari jenis apa pun. new Ketika operator digunakan untuk mengalokasikan objek dari jenis kelas tempat operator new didefinisikan, kelas tersebut operator new dipanggil.

operator new Fungsi yang ditentukan untuk kelas adalah fungsi anggota statis (yang tidak dapat menjadi virtual) yang menyembunyikan fungsi global operator new untuk objek dari jenis kelas tersebut. Pertimbangkan kasus di mana new digunakan untuk mengalokasikan dan mengatur memori ke nilai tertentu:

#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;
}

Argumen yang disediakan dalam tanda kurung ke new diteruskan ke Blanks::operator new sebagai chInit argumen. Namun, fungsi global operator new disembunyikan, menyebabkan kode seperti berikut menghasilkan kesalahan:

Blanks *SomeBlanks = new Blanks;

Kompilator mendukung array new anggota dan delete operator dalam deklarasi kelas. Contohnya:

class MyClass
{
public:
   void * operator new[] (size_t)
   {
      return 0;
   }
   void   operator delete[] (void*)
   {
   }
};

int main()
{
   MyClass *pMyClass = new MyClass[5];
   delete [] pMyClass;
}

Perilaku kegagalan alokasi

Fungsi new dalam Pustaka Standar C++ mendukung perilaku yang ditentukan dalam standar C++ sejak C++98. Ketika tidak ada cukup memori untuk permintaan alokasi, operator new melemparkan std::bad_alloc pengecualian.

Kode C++ yang lebih lama mengembalikan pointer null untuk alokasi yang gagal. Jika Anda memiliki kode yang mengharapkan versi non-throwing , newtautkan program Anda dengan nothrownew.obj. File nothrownew.obj menggantikan global operator new dengan versi yang mengembalikan nullptr jika alokasi gagal. operator newtidak lagi melempar .std::bad_alloc Untuk informasi selengkapnya tentang nothrownew.obj dan file opsi linker lainnya, lihat Opsi tautan.

Anda tidak dapat mencampur kode yang memeriksa pengecualian dari global operator new dengan kode yang memeriksa pointer null dalam aplikasi yang sama. Namun, Anda masih dapat membuat kelas lokal operator new yang berulah secara berbeda. Kemungkinan ini berarti pengkompilasi harus bertindak defensif secara default dan menyertakan pemeriksaan untuk pengembalian pointer null dalam new panggilan. Untuk informasi selengkapnya tentang cara mengoptimalkan pemeriksaan kompilator ini, lihat /Zc:throwingnew.

Menangani memori yang tidak mencukup

Cara Anda menguji alokasi yang gagal dari new ekspresi bergantung pada apakah Anda menggunakan mekanisme pengecualian standar, atau Anda menggunakan pengembalian nullptr . Standard C++ mengharapkan alokator untuk melemparkan salah satu std::bad_alloc atau kelas yang berasal dari std::bad_alloc. Anda dapat menangani pengecualian seperti yang ditunjukkan dalam sampel ini:

#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;
   }
}

Saat Anda menggunakan nothrow bentuk new, Anda dapat menguji kegagalan alokasi seperti yang ditunjukkan dalam sampel ini:

#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;
   }
}

Anda dapat menguji alokasi memori yang gagal saat Anda telah menggunakan nothrownew.obj file untuk menggantikan global operator new seperti yang ditunjukkan di sini:

#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;
   }
}

Anda dapat menyediakan handler untuk permintaan alokasi memori yang gagal. Dimungkinkan untuk menulis rutinitas pemulihan kustom untuk menangani kegagalan tersebut. Ini bisa, misalnya, merilis beberapa memori yang dipesan, lalu memungkinkan alokasi berjalan lagi. Untuk informasi selengkapnya, lihat _set_new_handler .

Operator delete

Memori yang dialokasikan secara dinamis menggunakan new operator dapat dibebaskan menggunakan delete operator. Operator penghapusan memanggil operator delete fungsi , yang membebaskan memori kembali ke kumpulan yang tersedia. delete Menggunakan operator juga menyebabkan destruktor kelas (jika ada) dipanggil.

Ada fungsi global dan cakupan operator delete kelas. Hanya satu operator delete fungsi yang dapat didefinisikan untuk kelas tertentu; jika ditentukan, fungsi global operator delete akan disembunyikan. Fungsi global operator delete selalu dipanggil untuk array dari semua jenis.

Fungsi global operator delete . Ada dua formulir untuk fungsi global operator delete dan anggota operator delete kelas:

void operator delete( void * );
void operator delete( void *, size_t );

Hanya salah satu dari dua bentuk sebelumnya yang dapat hadir untuk kelas tertentu. Formulir pertama mengambil satu argumen jenis void *, yang berisi penunjuk ke objek untuk dibatalkan alokasinya. Formulir kedua, alokasi berukuran besar, mengambil dua argumen: yang pertama adalah pointer ke blok memori untuk dibatalkan alokasinya, dan yang kedua adalah jumlah byte yang akan dibatalkan alokasinya. Jenis pengembalian kedua formulir adalah void (operator delete tidak dapat mengembalikan nilai).

Niat formulir kedua adalah untuk mempercepat pencarian kategori ukuran objek yang benar untuk dihapus. Informasi ini sering tidak disimpan di dekat alokasi itu sendiri, dan kemungkinan tidak di-cache. Formulir kedua berguna ketika operator delete fungsi dari kelas dasar digunakan untuk menghapus objek kelas turunan.

Fungsinya operator delete statis, sehingga tidak bisa virtual. Fungsi ini operator delete mematuhi kontrol akses, seperti yang dijelaskan dalam Kontrol Akses Anggota.

Contoh berikut menunjukkan fungsi dan operator delete yang ditentukan operator new pengguna yang dirancang untuk mencatat alokasi dan alokasi memori:

#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;
}

Kode sebelumnya dapat digunakan untuk mendeteksi "kebocoran memori", yaitu memori yang dialokasikan di toko gratis tetapi tidak pernah dibebaskan. Untuk mendeteksi kebocoran, global new dan delete operator didefinisikan ulang untuk menghitung alokasi dan alokasi memori.

Kompilator mendukung array new anggota dan delete operator dalam deklarasi kelas. Contohnya:

// 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;
}