Details the use of the new and delete operators in C++

  • 2020-05-07 20:13:17
  • OfStack

C++ supports the dynamic allocation and release of objects using the new and delete operators. These operators allocate memory for objects from a pool called free storage. The new operator calls the special function operator new, and the delete operator calls the special function operator delete.
In Visual C++.NET 2002, the new functionality in the standard C++ library will support the behavior specified in the C++ standard, and if the memory allocation fails, an std::bad_alloc exception will be thrown.
If the memory allocation fails, the new function of the C runtime also throws an std::bad_alloc exception.
If you still need a non-triggered version of new of the C runtime, please link your program to nothrownew.obj. However, when you link to nothrownew.obj, new in the standard C++ library no longer works.

calls the new operator
When
encounters the following statement in the program, it is converted to a call to the function operator new:


char *pch = new char[BUFFER_SIZE];

If the request is for zero-byte storage, operator new returns a pointer to a different object (that is, a repeat call to operator new returns a different pointer). If the allocation request does not have enough memory, operator new returns NULL or throws an exception (see for more information).
You can write routines that try to free memory and retry the allocation. For more information, see _set_new_handler. For more details on recovery scenarios, see the following topic: dealing with out-of-memory situations.
The following table describes two ranges of the operator new function.
The scope of the operator new function

运算符 范围
::operator new 全局
class-name ::operator new

The first parameter of operator new must be of type size_t (the type defined in STDDEF.H), and the return type is always void *.
The global operator new function is called when the new operator is used to assign objects of a built-in type, objects of a class type that do not contain user-defined operator new functions, and arrays of any type. When an object of a class type is assigned using the new operator, where operator new is defined, the operator new of that class is called.
The operator new function defined for the class is a static member function (therefore, it cannot be a virtual function) that hides the global operator new function for objects of this type. Consider the case where new is used to allocate memory and set it to a given value:


// spec1_the_operator_new_function1.cpp
#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;
}

The parameters supplied to new contained in parentheses are passed to chInit as Blanks::operator new parameters. However, the global operator new function will be hidden, resulting in the following code generation error:


Blanks *SomeBlanks = new Blanks;

In Visual C++ 5.0 and earlier versions, the global operator new function was always used for non-class types assigned with the new operator and for all arrays, whether or not they were of type class.
Starting with Visual C++ 5.0, the compiler supports the member array new and delete operators in the class declaration. Such as:


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

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

handles out of memory
can test the failed memory allocation through the following code:


// insufficient_memory_conditions.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
#define BIG_NUMBER 100000000
int main() {
 int *pI = new int[BIG_NUMBER];
 if( pI == 0x0 ) {
  cout << "Insufficient memory" << endl;
  return -1;
 }
}

Other ways to handle failed memory allocation requirements: write a custom recovery routine to handle such failures, and then register your function by calling the _set_new_handler runtime function.
delete operator
can use the delete operator to free up memory dynamically allocated using the new operator. The delete operator calls the operator delete function, which frees memory back to the available pool. Using the delete operator also results in a call to the class destructor, if any.
There are global and class-scoped operator delete functions. Only one operator delete function can be defined for a given class. If the function is defined, it hides the global operator delete function. Always call the global operator delete function for all types of arrays.
The global operator delete function (if declared) takes a single argument of type void *, which contains a pointer to the object to be released. The return type is void (operator delete cannot return a value). The operator delete function has two forms:


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

Only one of the first two variables exists in a given class. The first form runs as described for global operator delete. The second form takes two parameters, the first is a pointer to the block of memory to be freed, and the second is the number of bytes to be freed. The second form is especially useful when the operator delete function in the base class is used to remove objects from the derived class.
The operator delete function is static; So it can't be a virtual function. The operator delete function is subject to access control, as described in member access control.
The following example shows the user-defined operator new and operator delete functions for recording the allocation and release of memory:


// spec1_the_operator_delete_function1.cpp
// compile with: /EHsc
// arguments: 3
#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;
}

The previous code can be used to detect a "memory leak," or memory allocated in free storage but never freed. To perform this detection, the global new and delete operators should be redefined to calculate the allocation and release of memory.
Starting with Visual C++ 5.0, the compiler supports the member array new and delete operators in the class declaration. Such as:


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


Related articles: