我在哪些情况下使用malloc vs new?

我在C ++中看到有多种分配和释放数据的方法,我知道当你调用malloc时应该free调用,当你使用new操作符时,你应该配对delete ,混合两者是错误的(例如,Calling 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关键字没有类似reallocrealloc函数可能能够更有效地扩展一块内存的大小。

值得一提的是,你不能混用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

简短的答案是:不要使用malloc for C ++,但没有充分的理由这么做。 malloc具有许多不足之处与C ++,它用来当new定义来克服。

新的C ++代码修复了缺陷

  • 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
    }
    
  • 但比这还糟糕。 如果所讨论的类型是POD(普通的旧数据),那么你可以半理性地使用malloc来为它分配内存,就像第一个例子中的f2那样。

    如果某种类型是POD,它并不是那么明显。 事实上,给定类型可能会从POD更改为非POD,而不会导致编译器错误,并且可能很难调试问题,这是一个重要因素。 例如,如果有人(可能是另一位程序员,在维护期间,很多时候会做出更改,导致foo不再是POD,那么编译时就不会出现明显的错误,例如:

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

    会使f2malloc也变得不好,没有任何明显的诊断。 这里的示例很简单,但可能会意外地将非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。

  • 如果分配失败, malloc返回NULLnew会抛出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;
    }
    
  • 从根本上讲, malloc是C特性, new特性是C ++特性。 因此, 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();
    }
    
  • 我们的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和placement new那么你可以使用new来开始!


  • 从C ++ FQA Lite开始:

    [16.4]为什么我应该使用new而不是可靠的旧malloc()?

    FAQ:new / delete调用构造函数/析构函数; 新是类型安全的,malloc不是; 新的可以被一个类覆盖。

    FQA:FAQ提到的新特性不是美德,因为构造函数,析构函数和运算符重载都是垃圾(看看没有垃圾回收会发生什么?),类型安全问题在这里非常小(通常你有将malloc返回的void *转换为正确的指针类型,将其分配给一个类型化的指针变量,这可能很烦人,但远非“不安全”)。

    哦,并且使用可靠的旧malloc可以使用同样值得信赖和旧的realloc。 太糟糕了,我们没有一个闪亮的新运营商更新或什么。

    尽管如此,即使语言是C ++,new也不足以证明与一种语言使用的通用风格的偏差。 特别是,如果你只是简单地使用malloc对象,那么带有不平凡构造函数的类将会以致命的方式行事不端。 那么为什么不在整个代码中使用新的? 人们很少重载运营商新的,所以它可能不会太多。 如果他们超载新的,你总是可以让他们停下来。

    对不起,我无法抗拒。 :)

    链接地址: http://www.djcxy.com/p/2211.html

    上一篇: In what cases do I use malloc vs new?

    下一篇: How do I convert a String to an InputStream in Java?