34
  1. 考虑:

    char *p=NULL;
    free(p) // or
    delete p;
    

    如果我使用freeand deleteon会发生什么p

  2. 如果一个程序需要很长时间执行,比如 10 分钟,有没有办法将其运行时间减少到 5 分钟?

4

7 回答 7

72

关于 new/delete 和 malloc/free 的一些性能说明:

malloc 和 free分别调用构造函数和解构函数。这意味着您的类不会自动初始化或取消初始化,这可能很糟糕(例如未初始化的指针)!不过,这对于像 char 和 double 这样的 POD 数据类型无关紧要,因为它们实际上并没有 ctor。

new 和 delete确实调用了构造函数和解构函数。这意味着您的类实例会自动初始化和取消初始化。但是,通常会影响性能(与普通分配相比),但这是为了更好。

我建议与 new/malloc 的用法保持一致,除非你有理由(例如 realloc)。这样,您的依赖项就会减少,从而减少您的代码大小和加载时间(尽管只有一点点)。此外,您不会因为释放分配给 new 的东西或删除分配给 malloc 的东西而搞砸。(这很可能会导致崩溃!)

于 2008-11-30T18:03:12.193 回答
13

答案 1:两者都free(p)可以delete p使用 NULL 指针正常工作。

答案 2:没有看到代码的慢部分就无法回答。您应该分析代码!如果您使用的是 Linux,我建议使用 Callgrind(Valgrind的一部分)来找出执行的哪些部分花费的时间最多。

于 2008-11-30T13:13:57.347 回答
10

问题一:什么都不会发生。

从 ISO/IEC 14882(或:C++)的当前草案:

20.8.15 C 库 [c.malloc]

[of 的内容<cstdlib>,即:where freelives,] 与标准 C 库 [(参见 intro.refs 的内容)] header 相同<stdlib.h>,但有以下更改:[没有影响这个答案]。

因此,根据 ISO/IEC 9899:1999(或:C):

7.20.3.2free功能

如果 [the] ptr[parameter] 是空指针,则不会发生任何操作

再次来自 C++ 标准,有关delete此时间的信息:

3.7.4.2 释放函数 [basic.stc.dynamic.deallocation]

提供给释放函数的第一个参数的值可以是空指针值;如果是这样,并且如果释放函数是标准库中提供的函数,则调用无效

也可以看看:

于 2008-11-30T14:40:08.950 回答
4

如果您使用 NULL 参数调用 free 或使用 NULL 操作数删除,则不会发生任何事情。两者都被定义为接受 NULL 并且不执行任何操作。

您可以在 C++ 代码中更改任何数量的东西,这会影响它的运行速度。通常最有用的(按大致顺序)是:

  • 使用好的算法。这是一个很大的话题,但是例如,我最近通过使用 std::vector 而不是 std::list 将一些代码的运行时间减半,以防元素仅在最后添加和删除.
  • 避免重复冗长的计算。
  • 避免不必要地创建和复制对象(但是每分钟发生少于 1000 万次的任何事情都不会产生任何显着差异,除非您正在处理非常大的东西,例如包含 1000 万个项目的向量)。
  • 编译优化。
  • 将常用函数(同样,在 10 分钟运行时调用超过 1 亿次的任何函数)标记为内联。

话虽如此,分而治之是绝对正确的——除非你知道它花时间做什么,否则你无法有效地加速你的程序。有时,当您知道代码是如何工作的时,可以正确猜到这一点,而其他时候则非常令人惊讶。所以最好是剖析。即使您无法分析代码以准确查看时间花费的位置,但如果您衡量您的更改有什么影响,您通常最终可以弄清楚。

于 2008-11-30T14:27:22.237 回答
2

关于问题 2:
以前的答案非常好。但我只是想添加一些关于预优化的内容。假设一个中等复杂度的程序,90/10 规则通常适用——即 90% 的执行时间花在 10% 的代码上。“优化”的代码通常更难阅读和维护。所以,总是先解决问题,然后看看瓶颈在哪里(分析是一个很好的工具)。

于 2008-11-30T14:35:32.220 回答
2

正如其他人指出的那样,删除(或释放)NULL 指针不会做任何事情。但是,如果您分配了一些内存,那么是使用 free() 还是 delete 取决于您用于分配它们的方法。例如,如果你使用 malloc() 来分配内存,那么你应该使用 free(),如果你使用 new 来分配,那么你应该使用 delete。但是,请注意不要混合内存分配。使用单一方式分配和解除分配它们。

对于第二个问题,如果不看实际代码,很难一概而论。应根据具体情况进行处理。

于 2008-11-30T17:30:50.043 回答
1

很好的答案。

在性能问题上,提供了一种大多数人无法想象的方法,但少数人知道它确实有效,而且效果非常好。

90/10 规则是正确的。根据我的经验,通常有多个问题点,它们通常位于调用堆栈的中层。它们通常是由使用过度通用的数据结构引起的,但是除非您已经证明它确实是一个问题,否则您永远不应该修复某些东西。性能问题令人惊讶地无法预测。

修复任何单个性能问题可能无法为您提供所需的加速,但是您修复的每个问题都会使其余问题占用更大百分比的剩余时间,因此它们变得更容易找到。加速以复合方式组合在一起,因此您可能会对最终结果感到惊讶。

当您再也找不到可以解决的重大问题时,您已经尽了最大努力。有时,到那时,重新设计(例如使用代码生成)可以引发进一步的加速。

于 2008-11-30T22:41:35.187 回答