Malloc vs New for Primitives



我理解在C++中使用new对抗malloc的好处。但是对于特定情况,例如原始数据类型(非数组)-intfloat等,使用malloc比使用new更快吗?

虽然,即使对于原语也始终建议使用new,如果我们分配一个数组以便我们可以使用delete[].

但是对于非数组分配,我认为不会有任何构造函数调用int?因为,new运算符分配内存,检查它是否已分配,然后调用构造函数。但是仅对于原语非数组堆分配,使用malloc比使用new更好吗?

请指教。

永远不要在C++中使用malloc。切勿使用new,除非您正在实现低级内存管理原语。

建议是:

  • 问问自己:"我需要动态内存分配吗?很多时候你可能不需要它 - 更喜欢而不是指针,并尝试使用堆栈。

  • 如果您确实需要动态内存分配,请问问自己"谁将拥有分配的内存/对象?

    • 如果您只需要一个所有者(这很可能),您应该 使用std::unique_ptr.这是一个零成本的抽象new/delete.(可以指定不同的解除分配器。

    • 如果需要共享所有权,则应使用std::shared_ptr这不是一个零成本的抽象,因为它使用原子操作和一个额外的"控制块"来跟踪所有所有者。


如果您特别要处理数组,标准库提供了两个功能强大且安全的抽象,不需要任何手动内存管理:

  • std::array<T, N>:类型为TN元素的固定数组。

  • std::vector<T>:类型为T的可调整大小的元素数组。

std::arraystd::vector应满足 99% 的"阵列需求"。


还有一件重要的事情:标准库提供了应始终用于创建智能指针实例的std::make_uniquestd::make_shared。有几个很好的理由:

  • 更短 - 无需重复T(例如std::unique_ptr<T>{new T}),无需使用new

  • 更异常安全。它们可以防止由于函数调用中缺少明确定义的计算顺序而导致的潜在内存泄漏。例如

    f(std::shared_ptr<int>(new int(42)), g())
    

    可以按以下顺序进行评估:

    1. new int(42)
    2. g()

    如果g()投掷,int就会泄漏。

  • 更高效(在运行时速度方面)。这仅适用于std::make_shared- 使用它而不是直接std::shared_ptr允许实现为对象和控制块执行单个分配。

您可以在此问题中找到更多信息。

当您与使用纯 C 指定的 API 交互时,仍然需要在C++中使用mallocfree,因为不能保证安全地使用free来释放分配了operator new的内存(这最终是所有托管内存类使用的内存),也不能保证使用operator delete来释放分配的内存malloc

一个典型的例子是POSIXgetline(不要与std::getline混淆):它需要一个指向char *变量的指针;该变量必须指向分配了malloc的内存块(或者它可以是NULL,在这种情况下,getline将为你调用malloc);当你调用完getline时,你应该在该变量上调用free

同样,如果您正在编写库,则在内部使用C++但为外部调用方定义extern "C"API 是有意义的,因为这可以为您提供更好的二进制接口稳定性和跨语言互操作性。 如果您将堆分配的 POD 对象返回给调用方,您可能希望让他们使用free解除分配这些对象;他们不一定能使用delete,并且在不需要析构函数类型的操作时调用YourLibraryFree是不合人体工程学的。

实现可调整大小的容器对象时,可能仍然需要使用malloc,因为没有等效的realloc用于operator new

但正如其他答案所说,当您没有这种接口约束束缚您的手时,请改用其中一个托管内存类。

使用new总是更好。如果您使用malloc您仍然需要手动检查是否分配了空间。

在现代 c++ 中,您可以使用智能指针。有了make_uniquemake_shared,你从不明确地打电话给newstd::unique_ptr不大于基础指针,使用它的开销最小。

"我应该使用new还是malloc">的答案是单一责任规则

资源管理应由以此为唯一目的的类型完成。
这些类已经存在,例如unique_ptrvector等。

直接使用mallocnew是主要的罪过。

> zwol 的答案已经给出了正确的正确答案:仅在与 C 接互时使用malloc()/free()
我不会重复这些细节,我将回答性能问题。

事实是,malloc()new的表现可以而且确实不同。当你使用new执行分配时,内存通常通过调用全局operator new()函数来分配,这与malloc()不同。通过调用 tomalloc()来实现operator new()是微不足道的,但这不一定是这样做的。

事实上,我见过一个系统,其中调用malloc()operator new()每次调用的性能将比operator new()的标准实现高出大约 100 个 CPU 周期。这绝对是一个可衡量的差异,并且清楚地表明标准实现与malloc()非常不同。

因此,如果您担心性能,有三件事要做:

  1. 衡量您的绩效。

  2. 为全局operator new()函数及其友节点编写替换实现。

  3. 衡量您的绩效并进行比较。

收益/损失可能很大,也可能不大。

最新更新