new ve delete işleçleri

C++ ve işleçlerini kullanarak nesnelerin dinamik ayırmasını ve delete serbest bırakılıp ayrılmasını new destekler. Bu işleçler, boş depo (yığın olarak da bilinir) adlı bir havuzdan nesneler için bellek ayırır. new işleci özel işlevinioperator new, işleci ise delete özel işlevini operator deleteçağırır.

C Çalışma Zamanı Kitaplığı ve C++ Standart Kitaplığı'ndaki kitaplık dosyalarının listesi için bkz . CRT Kitaplığı Özellikleri.

İşleç new

Derleyici, bunun gibi bir deyimini işlevine operator newyönelik bir çağrıya çevirir:

char *pch = new char[BUFFER_SIZE];

İstek sıfır bayt depolama içinse, operator new ayrı bir nesneye yönelik bir işaretçi döndürür. Başka bir ifadeyle, farklı işaretçiler döndürmek için operator new tekrarlanan çağrılar.

Ayırma isteği için yetersiz bellek varsa, operator new bir std::bad_alloc özel durum oluşturur. Alternatif olarak, yerleştirme formunu new(std::nothrow)kullandıysanız veya oluşturmayan operator new destekte bağlantı sağladıysanız döndürürnullptr. Daha fazla bilgi için bkz . Ayırma hatası davranışı.

İşlevler için operator new iki kapsam aşağıdaki tabloda açıklanmıştır.

İşlevlerin operator new kapsamı

İşleç Scope
::operator new Global
sınıf adı::operator new Sınıf

öğesinin operator new ilk bağımsız değişkeni türünde size_tolmalıdır ve dönüş türü her zaman void*olur.

İşleç yerleşik türlerdeki nesneleri, kullanıcı tanımlı operator new işlevler içermeyen sınıf türü nesnelerini ve herhangi bir türde dizileri ayırmak için kullanıldığında genel operator new işlev çağrılırnew. işleci, bir öğesinin new tanımlandığı operator new bir sınıf türündeki nesneleri ayırmak için kullanıldığında, bu sınıfın operator new çağrılır.

Bir operator new sınıf için tanımlanan işlev, bu sınıf türündeki nesneler için genel operator new işlevi gizleyen bir statik üye işlevidir (sanal olamaz). Belleği ayırmak ve belirli bir değere ayarlamak için kullanılan durumu new göz önünde bulundurun:

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

için parantez new içinde sağlanan bağımsız değişken bağımsız değişken olarak chInit geçirilirBlanks::operator new. Ancak genel operator new işlev gizlenir ve aşağıdaki gibi bir kodun hata oluşturmasına neden olur:

Blanks *SomeBlanks = new Blanks;

Derleyici, sınıf bildiriminde üye dizisini new ve delete işleçleri destekler. Örnek:

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

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

Ayırma hatası davranışı

new C++ Standart Kitaplığı'ndaki işlev, C++98'den bu yana C++ standardında belirtilen davranışı destekler. Ayırma isteği için bellek yetersiz olduğunda bir operator newstd::bad_alloc özel durum oluşturur.

Eski C++ kodu başarısız ayırma için null işaretçi döndürdü. oluşturmayan sürümünü newbekleyen kodunuz varsa programınızı ile nothrownew.objbağlayın. Dosya, nothrownew.obj genel operator new değerini ayırma başarısız olursa döndüren nullptr bir sürümle değiştirir. operator new artık atmıyor std::bad_alloc. Ve diğer bağlayıcı seçeneği dosyaları hakkında nothrownew.obj daha fazla bilgi için bkz . Bağlantı seçenekleri.

Aynı uygulamadaki null işaretçileri denetleen kodla genelden operator new özel durumları denetleen kodu karıştıramazsınız. Ancak, yine de farklı davranan sınıf-yerel operator new oluşturabilirsiniz. Bu olasılık, derleyicinin varsayılan olarak savunmada hareket etmesi ve çağrılarda new null işaretçi dönüşleri için denetimler içermesi gerektiği anlamına gelir. Bu derleyici denetimlerini iyileştirmenin bir yolu hakkında daha fazla bilgi için bkz /Zc:throwingnew. .

Yetersiz belleği işleme

Bir ifadeden new başarısız ayırma için test yönteminiz, standart özel durum mekanizmasını mı yoksa bir dönüş mü kullandığınıza nullptr bağlıdır. Standart C++ ayırıcının veya std::bad_alloc öğesinden türetilmiş bir sınıf oluşturmasını std::bad_allocbekler. Bu örnekte gösterildiği gibi böyle bir özel durumu işleyebilirsiniz:

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

biçimini newkullandığınızdanothrow, bu örnekte gösterildiği gibi bir ayırma hatası için test edebilirsiniz:

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

Burada gösterildiği gibi geneli operator new değiştirmek için dosya kullandığınızda nothrownew.obj başarısız bellek ayırmayı test edebilirsiniz:

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

Başarısız bellek ayırma istekleri için bir işleyici sağlayabilirsiniz. Böyle bir hatayı işlemek için özel bir kurtarma yordamı yazmak mümkündür. Örneğin, ayrılmış bellek serbest bırakılabilir ve ayırmanın yeniden çalıştırılmasına izin verebilir. Daha fazla bilgi için bkz. _set_new_handler.

İşleç delete

işleci kullanılarak new dinamik olarak ayrılan bellek, işleci kullanılarak delete serbestleştirilebilir. Delete işleci, kullanılabilir havuza geri bellek boşaltan işlevini çağırır operator delete . işlecinin delete kullanılması sınıf yıkıcısının (varsa) çağrılmasına da neden olur.

Genel ve sınıf kapsamlı operator delete işlevler vardır. operator delete Belirli bir sınıf için yalnızca bir işlev tanımlanabilir; tanımlanırsa genel operator delete işlevi gizler. Genel operator delete işlev her zaman herhangi bir türde diziler için çağrılır.

Genel operator delete işlev. Genel operator delete ve sınıf üyesi operator delete işlevleri için iki form vardır:

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

Belirli bir sınıf için önceki iki biçimden yalnızca biri mevcut olabilir. İlk form, serbest bırakılan nesnenin işaretçisini içeren türünde void *tek bir bağımsız değişken alır. İkinci form olan boyutlu serbest bırakma iki bağımsız değişken alır: birincisi serbest bırakmak için bellek bloğunun işaretçisidir ve ikincisi serbest bırakılanın bayt sayısıdır. Her iki formun da dönüş türü ( voidoperator delete değer döndüremez).

İkinci formun amacı, silinecek nesnenin doğru boyut kategorisini aramayı hızlandırmaktır. Bu bilgiler genellikle ayırmanın kendisine yakın bir noktada depolanmaz ve büyük olasılıkla çıkarılmamıştır. İkinci form, türetilmiş bir sınıfın nesnesini silmek için temel sınıftan bir işlev kullanıldığında kullanışlıdır operator delete .

operator delete İşlev statik olduğundan sanal olamaz. İşlev, operator delete Üye Erişim Denetimi'nde açıklandığı gibi erişim denetimine uyar.

Aşağıdaki örnekte, bellek ayırmalarını ve operator delete serbest bırakmalarını günlüğe kaydetmek için tasarlanmış kullanıcı tanımlı operator new ve işlevler gösterilmektedir:

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

Yukarıdaki kod, "bellek sızıntısını" yani boş depoda ayrılan ancak hiçbir zaman serbest bırakılmayan belleği algılamak için kullanılabilir. Sızıntıları algılamak için, genel new ve delete işleçler belleği ayırma ve ayırmayı saymak için yeniden tanımlanır.

Derleyici, sınıf bildiriminde üye dizisini new ve delete işleçleri destekler. Örnek:

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