2012-05-14 2 views
5

C++에서 배치 new 구문에 관한 질문이 있습니다. 다음 두 코드 조각은 기능상으로 동일하며 서로 교환하여 사용할 수 있습니다 (첫 번째 코드가 적합 할 때 두 번째 코드를 사용해야 함을 의미하지는 않습니다).게재 위치 새 동작 해당 사항

# 1

T* myObj = new T(); 
// Do something with myObj 
delete myObj; 

# 2

char* mem = new char[sizeof(T)]; 
T* myObj = new (mem) T(); 
// Do something with myObj 
myObj->~T(); 
delete[] mem; 

뭔가 내가이 같은 배치 새 구문을 사용하고 때 나는 특히주의해야 있습니까? 당신은 원시 메모리를 할당하고 있기 때문에

답변

11

이들은 생성자 또는 소멸자가 T 인 경우 서로 다른 동작을하기 때문에 동일하지 않습니다.

new T()은 예외를 전파하기 전에 할당 된 메모리를 해제합니다. char* mem = new char[sizeof(T)]; T* myObj = new (mem) T();은 공개되지 않습니다. 마찬가지로 delete myObj~T()이 던져 놓든지 상관없이 항상 메모리를 할당 해제합니다.

T* myObj = new T();/*other code*/delete myObj;에 대한 정확한 상응하는 같은 것 : 기본적인 수준에

//When using new/delete, T::operator new/delete 
//will be used if it exists. 
//I don't know how do emulate this in 
//a generic way, so this code just uses 
//the global versions of operator new and delete. 
void *mem = ::operator new(sizeof(T)); 
T* myObj; 
try { 
    myObj = new (mem) T(); 
} 
catch(...) { 
    ::operator delete(mem); 
    throw; 
} 
/*other code*/ 
try { 
    myObj->~T(); 
    ::operator delete(mem); 
} 
catch(...) { 
    //yes there are a lot of duplicate ::operator deletes 
    //This is what I get for not using RAII): 
    ::operator delete(mem); 
    throw; 
} 
+0

이 메모리는'새로운 문자가 할당 한 것 [는 sizeof (T)]'제대로 정렬 : 하나 common approach는 다음과? –

+3

@TadeuszKopec : 표준은 메모리가 가능한 최대 정렬을 보장합니다. 이것은 자연 정렬 (즉, 기본 제공 유형과 함께 표시)을 사용하는 경우에만 유지됩니다. 예를 들어, pragma를 사용하여 유형의 정렬을 최대, 즉 최대 두 배로 늘린 다음 모든 베팅을 해제하면됩니다. –

8

, 자세히 상응하는 것 : 특정 클래스에 대한 ::operator new 오버로드 한 경우, 이것은 당신이 new char []을 사용하여 해당 클래스의 operator new을 사용하는 것입니다

void *mem = operator new(sizeof(T)); 
T *myobj = new(mem) T(); 

// ... 

myobj->~T(); 
operator delete(mem); 

주 그것을 무시할 것이다.

편집 : 여기에 예외 가능성을 무시하고 있다고 덧붙여 야합니다. @ Mankarse의 대답은 그 부분을 상당히 잘 감추는 것처럼 보입니다.

0

을, 당신은 두 경우 모두에서 같은 일을하고있어 :하여 예 당신에게 힙에 새로운 객체를 인스턴스화하고있어 메모리를 공개하지만 두 번째 경우에는 배치 연산자 new 연산자를 사용합니다.

이 경우 두 경우 모두 Mankarse가 설명한대로 생성자가 throw하는 경우와 동일한 결과를 얻을 수 있습니다.

또한 두 번째 경우는 placement new의 실제적인 예가 아니기 때문에 서로 바꾸어서 사용할 수 있다고는 말할 수 없습니다. 아마도 placement new을 메모리 풀의 컨텍스트에서 사용하는 것이 더 바람직 할 것이며 자신의 메모리 관리자를 작성하여 할당 된 메모리에 여러 개의 T 객체를 배치 할 수 있습니다. (내 테스트에서 25 % CPU 시간). placement new에 대한보다 현실적인 사용 사례가있는 경우 걱정해야 할 사항이 더 많습니다.

0

글쎄, 당신은 T 개체에 대한 메모리를 미리 할당하고 있습니다. 그리고 괜찮을거야. 그럼에도 불구하고 할당 된 영역을 한 번 더 재사용하는 것이 좋습니다. 그렇지 않으면 느려질 것입니다.

0

예. 예를 들어 설명 하기엔 너무 간단하지만 미리 할당 한 메모리 인 "mem"는 "myObj"에 저장된 객체를 관리해야합니다."

아마도 시나리오, 더 나은 방법을 넣어 # 1가 힙 공간을 할당하고, 그 공간에있는 객체를 구축합니다. 시나리오 이 # 2가 힙에 공간을 할당,"MEM은 "다음 오브젝트를 구축 어딘가에 그 공간 내에서.

지금, 내 다른 곳 두 번째 객체를 넣어 "MEM."그것은 바로?

건설 및 두 시나리오 모두에서 동일하게 일어나고 myObj로 파괴 (제외 복잡해진다 C Mankarse가 지적한 바와 같이 예외를 던지는 생성자의 ase)하지만 할당자는 시나리오 # 1이 아니라 시나리오 # 2의 메모리 관리를 담당합니다.

"mem"을 적절하게 관리하는 데주의하십시오.

template<class T> void destroy(T* p, Arena& a) 
{ 
     if (p) { 
       p->~T();  // explicit destructor call 
       a.deallocate(p); 
     } 
} 
관련 문제