2

何时(如果有的话)可以在 C++ 中互换使用deletefree

我的担忧如下:假设malloc/freenew/的使用有不正确的混淆delete(更不用说new[]/了delete[])。但是deletefree做同样的事情;
幸运的是,这在测试中没有被发现。稍后这可能会导致生产崩溃。

我怎样才能执行某种检查来防止这种情况发生?如果两者混淆了,我会被警告吗?如果不是在编译时,也许是在运行时进行一些代码检测?我将如何处理这个?

这个问题的目的是找到避免无意中混淆用法的方法。

4

14 回答 14

11

避免混淆它们的简单方法是永远不要使用 malloc(),那么你永远不会想调用 free()。为避免此问题而创建的基础架构称为“代码审查”,但在这种情况下,代码库上的快速“grep malloc(”或“grep free(”)可能就足够了。

于 2009-07-22T16:32:56.193 回答
7

绝不。如果它有效,那完全是实施的意外。不要依赖这种行为。

于 2009-07-22T16:30:32.267 回答
5

要回答第二个问题,如果您同时控制malloc/freeoperator new/ delete,则可以存储额外的信息以与两者返回的指针相关联,这些指针告诉您它们是如何分配的。当指针传递给freeoroperator delete时,检查它是否由适当的函数分配。如果不是,则断言或引发异常,或者执行您所做的任何事情来报告不匹配。

通常这是通过分配额外的内存来完成的,例如,给定malloc(size)operator new(size),您在其中分配size + additional space和推送额外的信息。

于 2009-07-22T16:36:56.747 回答
5

确保您永远不会混淆它们的唯一方法是:

  • 一开始就不要使用 malloc/free,或者
  • 依靠 RAII 进行内存分配。保护 RAII 对象中的每个内存分配,以确保内存在超出范围时得到正确且一致的释放,或者将分配包装在智能指针中。

手动调用 deletefree 只是对 bug 的邀请。

于 2009-07-22T16:41:03.103 回答
4

您应该始终在 C++ 中使用newand delete,因为只有newanddelete才会调用对象的构造函数和析构函数。

如果您发现必须同时使用两者(例如,如果您正在与 C 库交互),那么彻底的代码审查应该仔细检查 的任何用途,free()以确定它们是否对应于 a malloc(),以及它们是否被用于一个 C 上下文。

于 2009-07-22T16:30:19.320 回答
1

如果我必须对其进行编码,我会在样式指南中添加如下内容:

  • free()只能在对象的私有指针字段上调用。
  • malloc()ed 缓冲区(或调用者必须从 C API 返回的缓冲区free())必须分配给对象的私有指针字段。
  • 持有可缓冲区的私有指针字段free()只能用于该目的。
  • 如果您使用匈牙利符号,请为其添加一个字母(如果您不使用,请不要)。
  • 通常free()只会在析构函数中调用,但在free()对象的生命周期内替换 -able 缓冲区时除外。在这种情况下,您可以free()在替换期间调用最近从私有字段中复制的值,而不是直接调用字段值。

换句话说,在任何使用 malloc/free 的东西上加上一个包装器。这个包装器可以是每个人都使用的单个模板,或者您可以允许将删除函数设置为free(). 然后在代码审查中,如果您在其他任何地方看到对 malloc/free 的调用,那就错了。

基本上,阻止这个问题的最好方法是在你的资源处理之上。在 C 中,人们不小心调用free()流而不是fclose().

于 2009-07-22T17:27:55.787 回答
0

在释放用 new 分配的东西时,您应该始终使用 delete 或 delete[]。malloc 和 free 也是如此。

如果使用 free 删除 new:ed 类,则不会正确调用析构函数。此外,new 和 delete 不一定使用 malloc/free 进行分配,因此您最终也可能会损坏堆。

于 2009-07-22T16:30:58.523 回答
0

切勿new/deletenew[]/delete[]或与混合malloc()/free()malloc()/free()最重要的是,至少在 C++ 中的使用是值得怀疑的。

确保您不会意外执行此操作的最简单方法是不要手动管理内存。在 C++ 中,有字符串和其他容器以及智能指针来处理内存管理。根本不需要手动执行此操作。(我不确定我记得我最后一次打字是否delete真的是我最后一次打字。但如果我没有记错的话,那一定是 2001 年或 2002 年。)

于 2009-07-22T16:42:48.653 回答
0

你可以编写你自己的函数版本,在 new/new[]/malloc 中分配一些额外的内存来跟踪是哪一个进行了分配。然后检查 delete/delete[]/free 是否使用了正确的函数来回收内存。您还可以通过这种方式检查诸如混合 new[] 和 delete(不带 [])之类的内容。您可能只想在调试版本中使用这些版本。

于 2009-07-22T16:51:40.510 回答
0

总是使用delete分配给的东西newdelete []分配给的东西new []free()分配使用的东西malloc()

new 和 new[] 从不同于 malloc() 的堆分配,使用错误的 free()/delete 将尝试从错误的堆中释放。

于 2009-07-22T16:36:06.657 回答
0

您可以尝试在您的应用程序上运行valgrind以查看它是否捕获任何内容。该手册特别提到了它能够捕获对内存块的错误释放函数的使用。但是,我认为在编译时没有办法做到这一点。

于 2009-07-22T16:52:34.080 回答
0

避免误用 malloc/free 或 new/delete 的一种方法是不要直接调用这些函数,而是通过包装层调用它们。在包装层,你可以管理自己分发的指针,并保证误用会显式出错。

于 2013-04-10T09:13:21.577 回答
-1

为什么不只计算 malloc 语句的总数并将其与 free 的总数相加呢?对新建和删除执行相同操作。该过程可以使用正则表达式自动化。

于 2009-07-22T16:57:40.420 回答
-2

我与此相关的一件事是在 C++ 中重新实现 malloc 和 free,以便它在后台调用 new/delete。这不是 最佳的,但它在较小的项目中已经足够好了。

于 2009-07-22T16:32:43.463 回答