关于c ++:在什么情况下我使用malloc vs new?

In what cases do I use malloc vs new?

我在C++中看到了分配和释放数据的多种方法,我知道当你调用EDCOX1,0的时候,你应该调用EDCOX1,1,当你使用EDCOX1,2的操作符时,你应该用EDCOX1,3来配对,这是一个错误,把两个混合起来(例如,调用EDCOX1,4),用EDCOX1(2)操作符创建的东西,但我不清楚我在现实生活中什么时候应该使用malloc/free,什么时候应该使用new/delete

如果你是C++专家,请让我知道你在这方面遵循的任何规则或惯例。


除非你被迫使用c,否则你不应该使用malloc。务必使用new

如果您需要大量数据,只需执行以下操作:

1
char *pBuffer = new char[1024];

尽管这不正确,但要小心:

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

相反,在删除数据数组时应该这样做:

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

EDCOX1的1 }关键字是C++的方式,它将确保您的类型将调用它的构造函数。new关键字的类型安全性也更高,而malloc根本不是类型安全的。

我认为使用malloc的唯一方法是,如果需要更改数据缓冲区的大小。new关键字与realloc没有类似的方式。realloc函数可以更有效地扩展内存块的大小。

值得一提的是,你不能把new/freemalloc/delete混在一起。

注意:此问题中的某些答案无效。

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


简短的回答是:对于C++,不要使用EDCOX1 0,没有这样做的充分理由。EDCOX1的0度在使用C++时有许多不足之处,定义了EDCOX1×2定义来克服。

新的C++代码缺陷

  • malloc在任何意义上都不是类型安全的。在C++中,需要从EDCOX1引用4返回。这可能会带来很多问题:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #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,那么在编译时不会出现您希望的明显错误,例如:

    1
    2
    3
    4
    struct foo {
      double d[5];
      virtual ~foo() { }
    };

    会使f2malloc也变差,没有任何明显的诊断。这里的例子很简单,但是可能会在更远的地方意外地引入非podness(例如,在基类中,通过添加非pod成员)。如果你有C++ 11/Boost,你可以使用EDCOX1×10来检查这个假设是正确的,如果不是的话,会产生错误:

    1
    2
    3
    4
    5
    6
    7
    #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函数来抛出异常或退出程序或调用一些处理程序:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #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。我们可以通过非默认构造函数的模板和可变模板来实现这一点:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    #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 Lite:

    [16.4] Why should I use new instead of
    trustworthy old malloc()?

    FAQ: new/delete call the
    constructor/destructor; new is type
    safe, malloc is not; new can be
    overridden by a class.

    FQA: The virtues of new mentioned by
    the FAQ are not virtues, because
    constructors, destructors, and
    operator overloading are garbage (see
    what happens when you have no garbage
    collection?), and the type safety
    issue is really tiny here (normally
    you have to cast the void* returned by
    malloc to the right pointer type to
    assign it to a typed pointer variable,
    which may be annoying, but far from
    "unsafe").

    Oh, and using trustworthy old malloc
    makes it possible to use the equally
    trustworthy & old realloc. Too bad we
    don't have a shiny new operator renew or something.

    Still, new is not bad enough to
    justify a deviation from the common
    style used throughout a language, even
    when the language is C++. In
    particular, classes with non-trivial
    constructors will misbehave in fatal
    ways if you simply malloc the objects.
    So why not use new throughout the
    code? People rarely overload operator
    new, so it probably won't get in your
    way too much. And if they do overload
    new, you can always ask them to stop.

    对不起,我就是忍不住。:)


    在C++中总是使用新的。如果需要非类型化内存块,可以直接使用operator new:

    1
    2
    3
    void *p = operator new(size);
       ...
    operator delete(p);


    使用mallocfree仅用于分配将由以C为中心的库和API管理的内存。使用newdelete(以及[]变体)来处理您控制的所有内容。


    美国vs malloc()

    1)new是运算符,而malloc()是一个函数。

    2)constructors malloc()new调用,而不。

    3)new归来的精确的数据类型,而malloc()返回void *。

    4)new永不返回零(on a while想掷malloc()返回零失效)

    5)reallocation内存处理new困境而malloc()by CAN


    在回答你的问题,你应该知道newmalloc和之间的差异。一个简单的差别:

    mallocallocates记忆,而记忆newallocates和调用对象的构造函数,你allocating记忆。

    所以,除非你限制到C,你应该永远不会使用malloc,尤其是当处理与C + +对象。a recipe for是破你的计划。

    因此,之间的差别相当freedelete是一样的。的差异是delete想呼叫你的destructor除了释放对象的内存。


    mallocnew有一个很大的区别。malloc分配内存。这对C来说很好,因为在C中,一个内存块是一个对象。

    在C++中,如果不处理POD类型(类似于C类型),则必须调用内存位置上的构造函数来实际存在对象。在C++中,非POD类型是非常常见的,因为许多C++特性使对象自动非POD。

    new分配内存并在该内存位置上创建一个对象。对于非pod类型,这意味着调用构造函数。

    如果你这样做:

    1
    non_pod_type* p = (non_pod_type*) malloc(sizeof *p);

    无法取消引用您获得的指针,因为它没有指向对象。在使用它之前,您需要对它调用一个构造函数(这是使用placement new完成的)。

    另一方面,如果你:

    1
    non_pod_type* p = new non_pod_type();

    您得到一个始终有效的指针,因为new创建了一个对象。

    即使是吊舱类型,两者之间也存在显著差异:

    1
    2
    pod_type* p = (pod_type*) malloc(sizeof *p);
    std::cout << p->foo;

    这段代码将打印一个未指定的值,因为malloc创建的pod对象没有初始化。

    使用new可以指定要调用的构造函数,从而获得定义良好的值。

    1
    2
    pod_type* p = new pod_type();
    std::cout << p->foo; // prints 0

    如果你真的想要它,你可以使用new获得未初始化的pod对象。有关更多信息,请参阅其他答案。

    另一个区别是失败时的行为。当它无法分配内存时,malloc返回一个空指针,而new抛出一个异常。

    前者要求您在使用前测试返回的每个指针,而后者总是生成有效的指针。

    由于这些原因,在C++代码中,您应该使用EDCOX1×1,而不是EDCOX1×0。但即便如此,您也不应该在"公开"中使用new,因为它获得了您稍后需要释放的资源。使用new时,应将其结果立即传递到资源管理类中:

    1
    std::unique_ptr<T> p = std::unique_ptr<T>(new T()); // this won't leak

    new做的一些事情,malloc没有:

  • new通过调用该对象的构造函数来构造该对象
  • new不需要对分配的内存进行类型转换。
  • 它不需要分配大量的内存,而是需要要构造的对象。
  • 所以,如果你使用malloc,那么你需要明确地做上面的事情,这并不总是实际的。另外,new可以超载,但malloc不能超载。


    如果您使用的数据不需要构造/销毁,需要重新分配(例如,大量整数),那么我认为malloc/free是一个不错的选择,因为它可以给您重新分配,这比新的memcpy删除快得多(它在我的Linux设备上,但我猜这可能取决于平台)。如果使用C++对象而不是POD,需要构建/销毁,那么必须使用新的和删除运算符。

    不管怎样,我不明白为什么你不应该同时使用这两种方法(前提是你释放了你的内存错误并删除了新分配的对象),如果你能利用重新分配给你的速度提升(有时是一个重要的,如果你重新分配了大量的pod数组)。

    除非你需要它,否则你应该坚持C++中的Neal/Delphi。


    如果你有C代码要移植到C++,你可能会在其中留下任何的MalCube()调用。对于任何新的C++代码,我建议使用新的代码。


    如果使用C++,则尝试使用Neal/Delphi,而不是MALOC/CALLC,因为它们是运算符。对于malloc/calloc,需要包含另一个头。不要在同一代码中混合使用两种不同的语言。它们的工作在各个方面都很相似,都从哈希表的堆段动态分配内存。


    从较低的角度来看,new将在提供内存之前初始化所有内存,而malloc将保留内存的原始内容。


    new想initialise默认值的正确位置的参考结构和链接在它本身。

    例如

    1
    2
    3
    4
    struct test_s {
        int some_strange_name = 1;
        int &easy = some_strange_name;
    }

    在这样的结构new struct test_s将返回一个initialised营运资料,在分配的版本有没有默认值和不initialised内部参考。


    动态分配是只有当生命所需的时间应比对象的范围不同(它会创建在本持有范围较小。也使你有一个更大的原因)和特异性的价值在保它不工作。

    例如:

    1
    2
    3
    4
    5
    6
    7
     std::vector<int> *createVector(); // Bad
     std::vector<int> createVector();  // Good

     auto v = new std::vector<int>(); // Bad
     auto result = calculate(/*optional output = */ v);
     auto v = std::vector<int>(); // Good
     auto result = calculate(/*optional output = */ &v);

    从11在C + +,我们std::unique_ptr处理与分配的内存,其中包含的所有的内存分配。std::shared_ptr什么当你要创建的持股。(你会需要这比你会期望在一个良好的程序)

    (这是需要变成:

    1
    2
    3
    4
    auto instance = std::make_unique<Class>(/*args*/); // C++14
    auto instance = std::make_unique<Class>(new Class(/*args*/)); // C++11
    auto instance = std::make_unique<Class[]>(42); // C++14
    auto instance = std::make_unique<Class[]>(new Class[](42)); // C++11

    17所以C + +类,你需要std::optionalCAN防止从内存分配

    1
    2
    3
    auto optInstance = std::optional<Class>{};
    if (condition)
        optInstance = Class{};

    他很快的"实例"的形式去了,他们的工作记忆的人。这是一个简单的所有权的转移:

    1
    2
    3
     auto vector = std::vector<std::unique_ptr<Interface>>{};
     auto instance = std::make_unique<Class>();
     vector.push_back(std::move(instance)); // std::move -> transfer (most of the time)

    当你需要new如此安静?几乎没有从11在C + +。在你使用最std::make_unique直到你得到一个点你在哪里打,转移通过原始指针所有权的API。

    1
    2
    3
    4
     auto instance = std::make_unique<Class>();
     legacyFunction(instance.release()); // Ownership being transferred

     auto instance = std::unique_ptr<Class>{legacyFunction()}; // Ownership being captured in unique_ptr

    C++ 98/03中,你需要做的手动内存管理。如果你在这个个案,尝试升级到一个新版本的标准。如果你正在粉刷:

    1
    2
    3
    4
     auto instance = new Class(); // Allocate memory
     delete instance;             // Deallocate
     auto instances = new Class[42](); // Allocate memory
     delete[] instances;               // Deallocate

    确保你在正确的轨道有一个没有任何内存泄漏!Don’t move语义带来的任何工作。

    所以,当我们需要做malloc在C + +?唯一的原因,将有效信息通过内存分配和初始化后,置入新的。

    1
    2
    3
    4
     auto instanceBlob = std::malloc(sizeof(Class)); // Allocate memory
     auto instance = new(instanceBlob)Class{}; // Initialize via constructor
     instance.~Class(); // Destroy via destructor
     std::free(instanceBlob); // Deallocate the memory

    就好了,上面的是有效的,这可以通过一个新的算子做为好。std::vector是一个好的例子。

    最后,我们有一个安静的房间里的大象:C。如果你有一个与在C库会分配内存在C + +代码的代码在C和释放(或其他方式),你是被迫使用malloc /自由。

    如果你忘了这一案例,虚拟函数、类成员函数。它是只允许在一个吊舱的结构。

    一些例外的规则:

    • 你是写一个标准库的高级数据结构是适当的WHERE malloc
    • 你有一个大的分配数量的内存(内存拷贝a 10GB的文件?)
    • 你要防止你使用某些模具结构
    • 你不需要店型

    newdelete操作符可以在类和结构上操作,而mallocfree只使用需要强制转换的内存块。

    使用new/delete将有助于改进代码,因为您不需要将分配的内存强制转换为所需的数据结构。


    考虑到罕见的病例使用malloc /自由/删除是不是新的,当你allocating然后reallocating(POD类型简单,需要的对象)使用realloc AS没有类似realloc函数在C + +(我本可以做更多的用C + +方法)。


    在下面的场景中,我们不能使用new,因为它调用构造函数。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    class  B  {
    private:
        B *ptr;
        int x;
    public:
        B(int n)  {
            cout<<"B: ctr"<<endl;
            //ptr = new B;  //keep calling ctr, result is segmentation fault
            ptr = (B *)malloc(sizeof(B));
            x = n;
            ptr->x = n + 10;
        }
        ~B()  {
            //delete ptr;
            free(ptr);
            cout<<"B: dtr"<<endl;
        }
    };

    malloc()用于在C中动态分配内存而同样的工作是用C++中的New()完成的。因此,不能混合使用两种语言的编码约定。如果你问一下calloc和malloc()之间的区别就好了。