문제

다음과 같은 C++가 있다고 가정해 보겠습니다.

char *p = new char[cb];
SOME_STRUCT *pSS = (SOME_STRUCT *) p;
delete pSS;

C++ 표준에 따라 안전합니까?다시 캐스팅해야 하나요? char* 그런 다음 사용 delete[]?소멸자가 없는 일반 데이터이기 때문에 대부분의 C++ 컴파일러에서 작동할 것이라는 것을 알고 있습니다.안전이 보장되나요?

도움이 되었습니까?

해결책

안전하다는 보장은 없습니다.C++ FAQ 라이트의 관련 링크는 다음과 같습니다.

[16.13] [] 일부 내장 유형의 배열을 삭제할 때(char, int, 등.)?

http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.13

다른 팁

아니요, 정의되지 않은 동작입니다. 컴파일러는 그럴듯하게 다른 작업을 수행할 수 있으며 C++ FAQ 항목에는 깡패 에 링크되어 말한다, operator delete[] 다른 작업을 수행하기 위해 과부하가 걸릴 수 있습니다. operator delete.때로는 무시할 수도 있지만, 그렇게 할 수 없는 경우에는 delete[]를 new[]와 일치시키는 습관을 들이는 것도 좋은 습관입니다.

나는 그것을 매우 의심한다.

메모리를 해제하는 의심스러운 방법이 많이 있습니다. 예를 들어 다음을 사용할 수 있습니다. delete 너의 char 배열(대신 delete[]) 아마도 잘 작동할 것입니다.나 블로그에 올렸던 이에 대해 자세히 설명합니다(자체 링크에 대해 사과하지만 모든 것을 다시 작성하는 것보다 쉽습니다).

컴파일러는 플랫폼만큼 문제가 되지 않습니다.대부분의 라이브러리는 기본 운영 체제의 할당 방법을 사용합니다. 이는 동일한 코드가 Mac과 Mac에서 다르게 동작할 수 있음을 의미합니다.윈도우 대리눅스.나는 이것의 예를 보았고 모든 것이 의심스러운 코드였습니다.

가장 안전한 접근 방식은 항상 동일한 데이터 유형을 사용하여 메모리를 할당하고 해제하는 것입니다.할당하는 경우 chars를 사용하여 다른 코드로 반환하는 경우 특정 할당/할당 해제 메서드를 제공하는 것이 더 나을 수 있습니다.

SOME_STRUCT* Allocate()
{
    size_t cb; // Initialised to something
    return (SOME_STRUCT*)(new char[cb]);
}

 

void Free(SOME_STRUCT* obj)
{
    delete[] (char*)obj;
}

(오버로드 new 그리고 delete 연산자도 옵션이 될 수 있지만 나는 이 작업을 결코 좋아하지 않습니다.)

C++ 표준 [5.3.5.2]에서는 다음을 선언합니다.

피연산자에 클래스 유형이있는 경우, 위에서 언급 한 전환 기능을 호출하여 피연산자가 포인터 유형으로 변환되며,이 섹션의 나머지 부분에 대해 원래 피연산자 대신 변환 된 피연산자가 사용됩니다.두 대안 모두에서, 삭제의 피연산자 값은 널 포인터 값 일 수있다. 널 포인터 값이 아닌 경우, 첫 번째 대안 (삭제 객체)에서 삭제의 피연산자 값은 비 배열 물체에 대한 포인터이거나 그러한 기본 클래스를 나타내는 서브 객체 (1.8)에 대한 포인터 여야합니다. 객체 (10 절).그렇지 않은 경우 동작은 정의되지 않습니다.두 번째 대안 (삭제 배열)에서 삭제의 피연산자 값은 이전 배열 새 발현에서 발생하는 포인터 값이어야합니다 .77) 그렇지 않은 경우 동작은 정의되지 않습니다.[ 메모:이는 Delete-Expression의 구문이 새 발현의 구문이 아닌 새로 할당 된 물체의 유형과 일치해야 함을 의미합니다.—끝 참고 ] [ 메모:const 유형에 대한 포인터는 삭제 발현의 피연산자 일 수 있습니다.삭제 발현의 피연산자로 사용되기 전에 포인터 표현의 구성 (5.2.11)을 캐스트 할 필요는 없습니다.—끝 참고 ]

이것은 제가 여기에 답변한 질문과 매우 유사한 질문입니다. 링크 텍스트

즉, C++ 표준에 따르면 안전하지 않습니다.어떤 이유로 인해 다음과 크기가 다른 메모리 영역에 SOME_STRUCT 개체를 할당해야 하는 경우 size_of(SOME_STRUCT) (그리고 더 큰 것이 좋습니다!) 그렇다면 전역과 같은 원시 할당 기능을 사용하는 것이 더 좋습니다. operator new 할당을 수행한 다음 배치를 통해 원시 메모리에 객체 인스턴스를 생성합니다. new.놓기 new 객체 유형에 생성자가 없으면 매우 저렴합니다.

void* p = ::operator new( cb );
SOME_STRUCT* pSS = new (p) SOME_STRUCT;

// ...

delete pSS;

이것은 대부분의 경우 작동합니다.다음과 같은 경우에는 항상 작동해야 합니다. SOME_STRUCT POD 구조체입니다.다음과 같은 경우에는 다른 경우에도 작동합니다. SOME_STRUCT의 생성자는 던지지 않으며, 만약 SOME_STRUCT 사용자 정의 연산자 삭제가 없습니다.이 기술을 사용하면 캐스트가 필요하지 않습니다.

::operator new 그리고 ::operator delete C++와 가장 가까운 것은 malloc 그리고 free 그리고 이것들은 (클래스 재정의가 없는 경우) 적절하게 호출됩니다. new 그리고 delete 표현은 (조심해서!) 조합해서 사용할 수 있습니다.

이 동안 ~해야 한다 SOME_STRUCT가 char*가 아니기 때문에(단지 typedef가 아닌 한) 안전하다고 보장할 수는 없을 것 같습니다.

또한, 다양한 유형의 참조를 사용하고 있으므로 *p 액세스를 계속 사용하고 메모리가 삭제되면 런타임 오류가 발생합니다.

메모리가 가리키는 경우에는 정상적으로 작동합니다. 그리고 당신이 가리키는 포인터는 모두 POD입니다.이 경우 소멸자는 어쨌든 호출되지 않으며 메모리 할당자는 메모리 내에 저장된 유형을 알거나 신경 쓰지 않습니다.

POD 유형이 아닌 경우 이것이 괜찮은 유일한 경우는 포인트가 포인터의 하위 유형인 경우입니다(예:Car with a Vehicle*)을 가리키고 있으며 포인터의 소멸자가 가상으로 선언되었습니다.

이것은 안전하지 않으며 지금까지의 응답 중 어느 것도 이 일의 광기를 충분히 강조하지 않았습니다.자신이 진짜 프로그래머라고 생각하거나 팀에서 전문 프로그래머로 일하고 싶다면 그렇게 하지 마세요.구조체에 소멸자가 없다고만 말할 수 있습니다. 지금은, 그러나 당신은 미래를 위해 불쾌한 컴파일러 및 시스템 특정 함정을 놓는 것입니다.또한 코드가 예상대로 작동하지 않을 수도 있습니다.당신이 바랄 수 있는 최선의 것은 그것이 충돌하지 않는다는 것이다.그러나 new를 통한 배열 할당은 바이트에 추가 메모리를 할당하는 경우가 많기 때문에 천천히 메모리 누수가 발생할 것으로 생각됩니다. 이전의 반환된 포인터에.당신은 당신이 생각하는 메모리를 해제할 수 없습니다.좋은 메모리 할당 루틴은 Lint 등과 같은 도구처럼 이러한 불일치를 포착해야 합니다.

단순히 그렇게 하지 말고, 그러한 터무니없는 생각을 하게 만든 사고 과정을 마음에서 제거하십시오.

malloc/free를 사용하도록 코드를 변경했습니다.MSVC가 일반 데이터(이 경우 SOME_STRUCT는 Win32 구조이므로 매우 간단한 C)에 대해 새로 만들기/삭제를 구현하는 방법을 알고 있지만 이것이 이식 가능한 기술인지 알고 싶었습니다.

그렇지 않기 때문에 나는 그런 것을 사용하겠습니다.

new/delete 대신 malloc/free를 사용하면 malloc과 free는 유형을 신경 쓰지 않습니다.

따라서 C와 유사한 POD(내장 유형 또는 구조체와 같은 일반 기존 데이터)를 사용하는 경우 일부 유형은 malloc하고 다른 유형은 해제할 수 있습니다. 작동하더라도 스타일이 좋지 않습니다..

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top