[c++] 어떤 경우에 malloc 및 / 또는 new를 사용합니까?

C ++에는 데이터를 할당하고 해제하는 여러 가지 방법이 있으며 전화를 걸면 이해합니다. malloc 를 걸고 연산자를 free사용할 때 new페어링해야 delete하며 두 가지를 혼합하는 것은 실수라는 것을 이해합니다 (예 : free()생성 된 무언가에 대한 호출) 와 new) 연산자,하지만 난 사용해야하는 경우에 명확하지 않다 malloc/ free내가 사용해야 할 때 new/ delete내 실제 프로그램입니다.

C ++ 전문가 인 경우 이와 관련하여 따르는 경험 규칙이나 규칙을 알려주십시오.



답변

C를 사용하지 않으면을 사용해서는 안됩니다 malloc . 항상 사용하십시오 new.

많은 양의 데이터가 필요한 경우 다음과 같이하십시오.

char *pBuffer = new char[1024];

이것이 올바르지는 않지만주의하십시오.

//This is incorrect - may delete only one element, may corrupt the heap, or worse...
delete pBuffer;

대신 데이터 배열을 삭제할 때이 작업을 수행해야합니다.

//This deletes all items in the array
delete[] pBuffer;

new키워드는 그 일의 C ++ 방법이며, 그것은 당신의 유형이 그 것이다 보장합니다 생성자가 호출 . new키워드는 더 형태 보증 된 반면 malloc입력-로부터 안전하지 않습니다 전혀.

내가 유용하다고 생각할 수있는 유일한 방법 은 데이터 버퍼크기malloc변경 해야하는 경우 입니다. new키워드는 같은 유사한 방법이 없습니다 realloc. 이 realloc기능은 메모리 청크 크기를보다 효율적으로 확장 할 수 있습니다.

new/ freemalloc/을 혼합 할 수는 없습니다 delete.

참고 :이 질문에 대한 일부 답변이 잘못되었습니다.

int* p_scalar = new int(5);  // Does not create 5 elements, but initializes to 5
int* p_array  = new int[5];  // Creates 5 elements


답변

짧은 대답은 mallocC ++에 사용하지 않는 것이 좋습니다. mallocC ++과 함께 사용 new하면 극복 할 수있는 많은 결함이 있습니다.

C ++ 코드의 새로운 기능으로 해결 된 결함

  1. malloc의미있는 방식으로 타입 안전하지 않습니다. C ++에서는에서 반환을 캐스트해야합니다 void*. 잠재적으로 많은 문제가 발생합니다.

    #include <stdlib.h>
    
    struct foo {
      double d[5];
    };
    
    int main() {
      foo *f1 = malloc(1); // error, no cast
      foo *f2 = static_cast<foo*>(malloc(sizeof(foo)));
      foo *f3 = static_cast<foo*>(malloc(1)); // No error, bad
    }
  2. 그래도 더 나쁘다. 문제의 유형이 POD (일반 데이터) 인 경우 첫 번째 예에서 malloc와 같이 반 감각으로 메모리를 할당 하는 데 사용할 수 있습니다 f2.

    유형이 POD인지는 분명하지 않습니다. 주어진 유형이 컴파일러 오류가 발생하지 않고 문제를 디버깅하기가 매우 어려워 POD에서 비 POD로 변경 될 수 있다는 사실이 중요한 요소입니다. 예를 들어, 유지 관리 중 누군가 나중에 foo더 이상 POD가 아닌 변경을 수행 한 경우 컴파일 타임에 원하는대로 명백한 오류가 나타나지 않습니다. 예를 들면 다음과 같습니다.

    struct foo {
      double d[5];
      virtual ~foo() { }
    };

    만들 것 mallocf2명백한 진단하지 않고, 또한이 될 나쁜. 여기의 예는 사소한 것이지만 실수로 비 POD를 훨씬 더 멀리 도입 할 수 있습니다 (예 : 기본 클래스에서 비 POD 멤버를 추가하여). C ++ 11 / boost is_pod가있는 경우이 가정이 올바른지 확인하고 올바르지 않은 경우 오류를 생성하는 데 사용할 수 있습니다 .

    #include <type_traits>
    #include <stdlib.h>
    
    foo *safe_foo_malloc() {
      static_assert(std::is_pod<foo>::value, "foo must be POD");
      return static_cast<foo*>(malloc(sizeof(foo)));
    }

    boost는 형식이 C ++ 11 또는 다른 컴파일러 확장이없는 POD인지 확인할 수 없지만 .

  3. mallocNULL할당이 실패하면를 반환 합니다. new던질 것 std::bad_alloc입니다. 나중에 NULL포인터를 사용하는 동작 은 정의되어 있지 않습니다. 예외가 발생하면 예외가 깨끗하고 오류의 원인에서 발생합니다. 포장 malloc모든 호출에서 적절한 검사와 함께하는 경향이 지루하고 오류가 보인다. (좋은 일을 모두 취소하기 위해서는 한 번만 잊어야합니다). 예외적으로 호출자가 의미있게 처리하기 NULL가 훨씬 어려운 수준에서 호출자가 처리 할 수있는 수준으로 전파 될 수 있습니다 . safe_foo_malloc예외를 발생 시키거나 프로그램을 종료하거나 핸들러를 호출하도록 함수를 확장 할 수 있습니다 .

    #include <type_traits>
    #include <stdlib.h>
    
    void my_malloc_failed_handler();
    
    foo *safe_foo_malloc() {
      static_assert(std::is_pod<foo>::value, "foo must be POD");
      foo *mem = static_cast<foo*>(malloc(sizeof(foo)));
      if (!mem) {
         my_malloc_failed_handler();
         // or throw ...
      }
      return mem;
    }
  4. 기본적 malloc으로 C 기능이며 newC ++ 기능입니다. 결과적 malloc으로 생성자와 잘 작동하지 않으므로 바이트 덩어리 할당 만 살펴 봅니다. safe_foo_malloc게재 위치를 사용하도록 추가 확장 할 수 있습니다 new.

    #include <stdlib.h>
    #include <new>
    
    void my_malloc_failed_handler();
    
    foo *safe_foo_malloc() {
      void *mem = malloc(sizeof(foo));
      if (!mem) {
         my_malloc_failed_handler();
         // or throw ...
      }
      return new (mem)foo();
    }
  5. 우리의 safe_foo_malloc기능은 매우 일반적이지 않습니다. 이상적으로는 모든 유형을 처리 할 수있는 것을 원할 것입니다 foo. 기본이 아닌 생성자를위한 템플릿 및 가변 템플릿을 사용하여이를 달성 할 수 있습니다.

    #include <functional>
    #include <new>
    #include <stdlib.h>
    
    void my_malloc_failed_handler();
    
    template <typename T>
    struct alloc {
      template <typename ...Args>
      static T *safe_malloc(Args&&... args) {
        void *mem = malloc(sizeof(T));
        if (!mem) {
           my_malloc_failed_handler();
           // or throw ...
        }
        return new (mem)T(std::forward(args)...);
      }
    };

    이제 우리가 지금까지 식별 한 모든 문제를 해결함에있어 기본 new연산자를 실제로 재창조했습니다 . 당신이 사용 malloc하고 배치 하려는 경우, 당신은 new뿐만 아니라 new시작 하는 데 사용할 수 있습니다 !


답변

로부터 C ++ FQA 라이트 :

[16.4] 신뢰할 수있는 오래된 malloc () 대신 new를 사용해야하는 이유는 무엇입니까?

FAQ : 생성자 / 소멸자를 호출 / 삭제합니다. new는 타입이 안전하고 malloc은 그렇지 않습니다. new는 클래스에 의해 재정의 될 수 있습니다.

FQA : 생성자, 소멸자 및 연산자 오버로딩이 가비지 (가비지 수집이 없을 때 발생하는 일 참조) 및 유형 안전 문제가 실제로 매우 작기 때문에 FAQ에서 언급 한 새로운 미덕은 미덕이 아닙니다. malloc이 리턴 한 void *를 올바른 포인터 유형으로 캐스트하여 유형이 지정된 포인터 변수에 할당합니다.

오, 신뢰할 수있는 오래된 malloc을 사용하면 똑같이 신뢰할 수 있고 오래된 realloc을 사용할 수 있습니다. 유감스럽게도 우리에게는 새로운 운영자 갱신이나 무언가가 없습니다.

그럼에도 불구하고, 언어가 C ++ 인 경우에도 언어 전체에 사용되는 공통 스타일과의 편차를 정당화하기에 충분하지 않은 것은 새로운 것이 아닙니다. 특히 사소하지 않은 생성자를 가진 클래스는 단순히 객체를 malloc하면 치명적인 방식으로 잘못 작동합니다. 그렇다면 코드 전체에서 new를 사용하지 않는 이유는 무엇입니까? 사람들은 운영자에게 새로운 과부하를 거의주지 않기 때문에 너무 방해가되지 않을 것입니다. 새로운 과부하가 발생하면 언제든지 중지하도록 요청할 수 있습니다.

죄송합니다. 저항 할 수 없었습니다. 🙂


답변

항상 C ++에서 new를 사용하십시오. 형식화되지 않은 메모리 블록이 필요한 경우 연산자 new를 직접 사용할 수 있습니다.

a
void *p = operator new(size);
   ...
operator delete(p);


답변

사용하다 malloc단지 C-중심의 라이브러리와 API에 의해 관리 될 것입니다 메모리를 할당합니다. 제어하는 모든 항목에 및 (및 변형)을 사용하십시오 .free newdelete[]


답변

새로운 대 malloc ()

1) new이다 연산자 반면malloc() A는 기능 .

2) 생성자new 호출 하지만 malloc()그렇지 않습니다.

3) 정확한 데이터 유형을new 반환 하는 동안malloc() 반환 무효 * .

4) new절대 반환하지 않습니다 NULL 동안 (실패가 발생합니다) malloc()반환 NULL을

5) 메모리의 재 할당에 의해 처리되지 않는 new동안 malloc()


답변

귀하의 질문에 대답하기 위해, 당신은 알아야 사이의 차이를 mallocnew . 차이점은 간단합니다.

malloc 메모리new 할당하고 메모리할당하고 메모리할당 하는 객체 의 생성자호출합니다 .

따라서 C로 제한되지 않는 한, 특히 C ++ 객체를 다룰 때 malloc을 사용해서는 안됩니다. 그것은 프로그램을 깨기위한 레시피 일 것입니다.

또한 사이의 차이 free와는 delete상당히 동일합니다. 차이점은 delete메모리를 비우는 것 외에도 객체의 소멸자를 호출 한다는 것입니다.