当前位置:  开发笔记 > 编程语言 > 正文

在什么情况下我使用malloc vs new?

如何解决《在什么情况下我使用mallocvsnew?》经验,为你挑选了10个好方法。

我在C++中看到有多种方式来分配和释放数据,我知道当你打电话给malloc你时应该打电话free,当你使用new操作员时你应该配对,delete将两者混合是错误的(例如,调用free()创建的东西)与new操作员),但我不知道何时应该使用malloc/ free何时应该在我的真实世界程序中使用new/ delete.

如果您是C++专家,请告诉我您在此方面遵循的任何经验法则或惯例.



1> Brian R. Bon..:

除非你被迫使用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


"除非你被迫使用C,否则你永远不应该使用malloc.总是使用新的." 为什么?这里的胜利是什么?对于我们需要构造的对象,但是对于内存块,你清楚地记录了两种编码错误的方法(在new中更容易捕获()vs []和不太容易捕获的不匹配数组vs scaler new和delete).对原始内存块使用new/delete的动机是什么?
请注意"永远不要使用X!" 没有解释原因.
如果您没有使用正确的删除**,结果是未定义的**.这是不正确的.事实上它可能会使事情的一部分正确或有时工作只是盲目的运气.
@KPexEA:即使某些编译器可能会修复您的错误,但首先制作它们仍然是错误的:)总是在适当的地方使用delete [].
@DeadMG:如果一个人正在创建一个供异步API函数使用的数组,那么`new []`不会比`std :: vector`更安全吗?如果使用`new []`,指针变为无效的唯一方法是通过显式`delete`,而为std :: vector`分配的内存在向量调整大小或离开范围时可能无效.(注意,当使用`new []`时,如果异步方法仍处于未决状态,则必须允许可能无法调用`delete`;如果可能需要放弃异步操作,则可能必须安排通过回调删除).
关于在调用delete [] foo时调用delete foo,一些编译器会自动修复这个并且不会泄漏,而其他编译器只会删除第一个条目并泄漏.我在一些代码中有一些这些,valgrind会为你找到它们.
类型安全的意思?任何人都可以详细说明吗?
永远不要使用`new []`和`delete []`,总是使用`std :: vector`.

2> Flexo..:

简短的回答是:如果没有malloc充分的理由,请不要使用C++.malloc与C++一起使用时有许多不足之处,C++ new被定义为可以克服.

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

    malloc以任何有意义的方式都不是类型安全的.在C++中,您需要转换来自void*.这可能会引入很多问题:

    #include 
    
    struct foo {
      double d[5];
    }; 
    
    int main() {
      foo *f1 = malloc(1); // error, no cast
      foo *f2 = static_cast(malloc(sizeof(foo)));
      foo *f3 = static_cast(malloc(1)); // No error, bad
    }
    

    但它比这更糟糕.如果有问题的类型是POD(普通旧数据),那么你可以半合理地使用它malloc来为它分配内存,就像f2第一个例子中那样.

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

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

    将使mallocf2也变得不好,没有任何明显的诊断.这里的示例是微不足道的,但是可能会意外地将非PODness引入更远的地方(例如,在基类中,通过添加非POD成员).如果您有C++ 11/boost,您可以使用它is_pod来检查这个假设是否正确,如果不是,则会产生错误:

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

    虽然boost 无法确定某个类型是否为没有C++ 11或其他编译器扩展的POD.

    mallocNULL如果分配失败则返回.new会扔std::bad_alloc.稍后使用NULL指针的行为是未定义的.抛出异常时会出现干净的语义,并且会从错误源中抛出异常.malloc在每次通话时使用适当的测试进行包装似乎很乏味且容易出错.(你只需要忘记一次撤消所有好的工作).可以允许异常传播到调用者能够合理地处理它的级别,其中NULL更有意义地传递回来.我们可以扩展我们的safe_foo_malloc函数来抛出异常或退出程序或调用一些处理程序:

    #include 
    #include 
    
    void my_malloc_failed_handler();
    
    foo *safe_foo_malloc() {
      static_assert(std::is_pod::value, "foo must be POD");
      foo *mem = static_cast(malloc(sizeof(foo)));
      if (!mem) {
         my_malloc_failed_handler();
         // or throw ...
      }
      return mem;
    }
    

    从根本上说malloc是C功能并且new是C++功能.结果malloc不能很好地与构造函数一起使用,它只关注分配一块字节.我们可以safe_foo_malloc进一步扩展我们的使用位置new:

    #include 
    #include 
    
    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 
    #include 
    #include 
    
    void my_malloc_failed_handler();
    
    template 
    struct alloc {
      template 
      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++使`struct`和`class`意味着基本相同;这太糟糕了; 我想知道是否有任何问题可以为POD保留`struct`,并且可能假定所有`class`类型都是非POD.由C++发明之前的代码定义的任何类型都必然是POD,所以我不认为向后兼容性会成为问题.将非POD类型声明为`struct`而不是`class`是否有优势?

3> Matthias Ben..:

来自C++ FQA Lite:

[16.4]为什么我应该使用new而不是值得信赖的旧malloc()?

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

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

哦,使用值得信赖的旧malloc可以使用同样值得信赖的旧realloc.太糟糕了,我们没有一个闪亮的新操作员更新或什么.

尽管如此,即使语言是C++,新的也不足以证明偏离整个语言使用的共同风格是正确的.特别是,如果只是对象进行malloc操作,那么具有非平凡构造函数的类将会以致命的方式行为异常.那么为什么不在整个代码中使用新的呢?人们很少会将操作员重新设置为新的,所以它可能不会过多地妨碍你.如果他们确实过载新的,你总是可以让他们停下来.

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


那是一场骚乱*!谢谢.
我不能认真对待这个评论,因为它清楚地表明了作者对C++的偏见.C++是一种用于创建面向性能的软件的语言,而垃圾收集器只能对其目标产生不利影响.我不同意你的全部答案!

4> Ferruccio..:

始终在C++中使用new.如果需要一个无类型内存块,可以直接使用operator new:

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


如果直接调用operator new,则需要将字节数作为参数进行分配.
`operator new`的反义词是`operator delete`.在类型为`void*`的表达式上调用`delete`并不是一个定义明确的操作.
有趣的是,当我需要像这样的原始数据缓冲区时,我总是只分配一个unsigned char数组.

5> dmckee..:

使用malloc用于分配要由C-中心库和API来管理内存.对您控制的所有内容使用和(以及变体).free newdelete[]


另请注意,编写良好的C库将隐藏malloc并在内部自由,这就是C程序员应该如何工作的.

6> Yogeesh H T..:

new vs malloc()

1)new是一个操作员,同时malloc()也是一个功能.

2)new调用构造函数,而不调用malloc().

3)new返回确切的数据类型,同时malloc()返回void*.

4)new将不会返回NULL(将抛出失败),而malloc()返回NULL

5)的存储器再分配不通过处理newmalloc()可以


嗨,对于第4点),可以指示new在失败时返回NULL.`char*ptr = new(std :: nothrow)char [323232];`

7> The Quantum ..:

要回答你的问题,你应该知道的区别mallocnew.区别很简单:

malloc 分配内存,同时new 分配内存并调用你正在为其分配内存的对象的构造函数.

因此,除非您被限制为C,否则不应使用malloc,尤其是在处理C++对象时.这将是破坏你的程序的一个秘诀.

此外之间的差别free,并delete是完全一样的.区别在于delete除了释放内存之外还将调用对象的析构函数.



8> R. Martinho ..:

malloc和之间有一个很大的区别new.malloc分配内存.这对于C来说很好,因为在C中,一块内存是一个对象.

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

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

如果您这样做:

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

您获取的指针无法解除引用,因为它不指向对象.在使用之前,您需要在其上调用构造函数(这是使用展示位置完成的new).

另一方面,如果你这样做:

non_pod_type* p = new non_pod_type();

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

即使对于POD类型,两者之间也存在显着差异:

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

这段代码会打印一个未指定的值,因为创建的POD对象malloc未初始化.

使用new,您可以指定要调用的构造函数,从而获得明确定义的值.

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

如果你真的想要它,你可以使用use new来获得未初始化的POD对象.有关详细信息,请参阅此其他答案.

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

前者要求您在使用之前测试返回的每个指针,而后者将始终生成有效的指针.

出于这些原因,您应该使用C++代码new,而不是malloc.但即便如此,您也不应该使用new"公开",因为它会获取您稍后需要释放的资源.使用时new,应将其结果立即传递到资源管理类:

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



9> herohuyongta..:

有一些事情new没有malloc做到:

    new 通过调用该对象的构造函数来构造对象

    new 不需要对已分配的内存进行类型转换.

    它不需要分配大量内存,而是需要构造许多对象.

所以,如果你使用malloc,那么你需要明确地做上面的事情,这并不总是实际的.另外,new可以重载但malloc不能.



10> PSkocik..:

如果您使用不需要构造/销毁并且需要重新分配的数据(例如,大量的int),那么我相信malloc / free是一个不错的选择,因为它可以为您提供重新分配,这比new-memcpy更快-delete(在我的Linux机器上,但是我想这可能取决于平台)。如果使用不是POD且需要构造/销毁的C ++对象,则必须使用new和delete运算符。

无论如何,我不明白为什么不应该同时使用两种方法(前提是您释放了已分配的内存并删除了用new分配的对象),如果可以利用速度提升的优势(如果您要重新分配大型数组,有时会很重要)重新分配可以给您的POD)。

除非您需要,否则应坚持使用C ++中的new / delete。

推荐阅读
有风吹过best
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有