newdelete 연산자

C++는 및 delete 연산자를 사용하여 개체의 동적 할당 및 할당 취소를 new 지원합니다. 이러한 연산자는 무료 저장소(힙이라고도 함)라는 풀의 개체에 대한 메모리를 할당합니다. 연산자는 new 특수 함수 operator new를 호출하고 연산자는 delete 특수 함수 operator delete를 호출합니다.

C 런타임 라이브러리 및 C++ 표준 라이브러리의 라이브러리 파일 목록은 CRT 라이브러리 기능을 참조 하세요.

연산자 new

컴파일러는 다음과 같은 문을 함수 operator new에 대한 호출로 변환합니다.

char *pch = new char[BUFFER_SIZE];

요청이 스토리지 operator new 의 0바이트인 경우 고유 개체에 대한 포인터를 반환합니다. 즉, 다른 포인터를 반환하는 operator new 반복 호출입니다.

할당 요청에 operator new 대한 메모리가 부족한 경우 예외를 std::bad_alloc throw합니다. 또는 배치 양식을 사용한 경우 또는 throw operator new 하지 않는 지원에 연결한 경우 반환 nullptrnew(std::nothrow)됩니다. 자세한 내용은 할당 실패 동작을 참조 하세요.

함수에 대한 operator new 두 가지 범위는 다음 표에 설명되어 있습니다.

함수 범위 operator new

작업 Scope
::operator new 전역
class-name::operator new 클래스

첫 번째 인수는 operator new 형식 size_t이어야 하며 반환 형식은 항상 void*.입니다.

전역 operator new 함수는 연산자를 new 사용하여 기본 제공 형식의 개체, 사용자 정의 operator new 함수를 포함하지 않는 클래스 형식의 개체 및 모든 형식의 배열을 할당할 때 호출됩니다. 연산자를 new 사용하여 정의된 클래스 형식의 개체를 operator new 할당하면 해당 클래스가 operator new 호출됩니다.

operator new 클래스에 대해 정의된 함수는 해당 클래스 형식의 개체에 대한 전역 operator new 함수를 숨기는 정적 멤버 함수(가상일 수 없음)입니다. 메모리를 할당하고 지정된 값으로 설정하는 데 사용되는 경우 new 를 고려합니다.

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

괄호 new 로 제공된 인수는 인수로 chInit 전달됩니다Blanks::operator new. 그러나 전역 operator new 함수가 숨겨져 다음과 같은 코드가 오류를 생성합니다.

Blanks *SomeBlanks = new Blanks;

컴파일러는 클래스 선언에서 멤버 배열 newdelete 연산자를 지원합니다. 예시:

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

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

할당 실패 동작

C++ 표준 라이브러리의 함수는 new C++98 이후 C++ 표준에 지정된 동작을 지원합니다. 할당 요청에 operator new 대한 메모리가 부족한 경우 예외를 std::bad_alloc throw합니다.

이전 C++ 코드는 실패한 할당에 대한 null 포인터를 반환했습니다. throw하지 않는 버전 new이 필요한 코드가 있는 경우 프로그램을 .와 nothrownew.obj연결합니다. 이 파일은 nothrownew.obj 할당이 실패할 경우 반환되는 버전으로 전역 operator new 으로 바뀝니다 nullptr . operator new은 더 이상 throw되지 않습니다.std::bad_alloc 링커 옵션 파일 및 기타 링커 옵션에 대한 nothrownew.obj 자세한 내용은 링크 옵션을 참조 하세요.

전역 operator new 예외에 대해 검사 코드를 동일한 애플리케이션의 null 포인터에 대해 검사 코드와 혼합할 수 없습니다. 그러나 다르게 동작하는 클래스 로컬 operator new 을 만들 수 있습니다. 이 가능성은 컴파일러가 기본적으로 방어적으로 작동하고 null 포인터 반환에 대한 검사 호출에 new 포함해야 한다는 것을 의미합니다. 이러한 컴파일러 검사 최적화하는 방법에 대한 자세한 내용은 다음을 참조하세요/Zc:throwingnew.

메모리 부족 처리

식에서 new 실패한 할당을 테스트하는 방법은 표준 예외 메커니즘을 사용하는지 또는 반환을 nullptr 사용하는지에 따라 달라집니다. 표준 C++에서는 할당자가 .에서 std::bad_alloc파생된 클래스 또는 std::bad_alloc 클래스를 throw해야 합니다. 이 샘플에 표시된 것처럼 이러한 예외를 처리할 수 있습니다.

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

형식newnothrow 사용하는 경우 다음 샘플에 표시된 대로 할당 실패를 테스트할 수 있습니다.

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

다음과 같이 파일을 사용하여 nothrownew.obj 전역 operator new 으로 대체한 경우 실패한 메모리 할당을 테스트할 수 있습니다.

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

실패한 메모리 할당 요청에 대한 처리기를 제공할 수 있습니다. 이러한 오류를 처리하는 사용자 지정 복구 루틴을 작성할 수 있습니다. 예를 들어 일부 예약된 메모리를 해제한 다음 할당이 다시 실행되도록 허용할 수 있습니다. 자세한 내용은 _set_new_handler를 참조하세요.

연산자 delete

연산자를 사용하여 동적으로 할당된 메모리는 연산자를 newdelete 사용하여 해제할 수 있습니다. delete 연산자는 함수를 operator delete 호출하여 메모리를 사용 가능한 풀로 다시 해제합니다. 연산자를 delete 사용하면 클래스 소멸자(있는 경우)도 호출됩니다.

전역 및 클래스 범위 operator delete 함수가 있습니다. 지정된 클래스에 대해 하나의 operator delete 함수만 정의할 수 있습니다. 정의된 경우 전역 operator delete 함수를 숨깁니다. 전역 operator delete 함수는 항상 모든 형식의 배열에 대해 호출됩니다.

전역 operator delete 함수입니다. 전역 operator delete 및 클래스 멤버 operator delete 함수에 대한 두 가지 양식이 있습니다.

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

지정된 클래스에 대해 앞의 두 양식 중 하나만 존재할 수 있습니다. 첫 번째 폼은 할당 취소할 개체에 대한 포인터를 포함하는 형식 void *의 단일 인수를 사용합니다. 두 번째 형식인 크기 할당 취소는 두 개의 인수를 사용합니다. 첫 번째는 할당 취소할 메모리 블록에 대한 포인터이고, 두 번째는 할당 취소할 바이트 수입니다. 두 폼의 반환 형식은 값(operator delete값을 반환할 수 없음)입니다 void .

두 번째 양식의 의도는 삭제할 개체의 올바른 크기 범주를 빠르게 검색하는 것입니다. 이 정보는 종종 할당 자체 근처에 저장되지 않으며 캐시되지 않을 수 있습니다. 두 번째 양식은 기본 클래스의 operator delete 함수를 사용하여 파생 클래스의 개체를 삭제하는 경우에 유용합니다.

함수는 operator delete 정적이므로 가상일 수 없습니다. 이 함수는 operator delete 멤버 액세스 제어에 설명된 대로 액세스 제어를 준수합니다.

다음 예제에서는 메모리 할당 및 operator delete 할당 취소를 기록하도록 설계된 사용자 정의 operator new 함수와 함수를 보여 줍니다.

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

위의 코드를 사용하여 "메모리 누수", 즉 무료 저장소에 할당되었지만 해제되지 않은 메모리를 검색할 수 있습니다. 누수를 감지하기 위해 전역 newdelete 연산자는 메모리 할당 및 할당 취소를 계산하도록 다시 정의됩니다.

컴파일러는 클래스 선언에서 멤버 배열 newdelete 연산자를 지원합니다. 예시:

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