【问题标题】:Checking to see if a pointer can be freed检查是否可以释放指针
【发布时间】:2011-06-02 04:10:40
【问题描述】:

我已经到处寻找答案,但似乎找不到。 (我对 C++ 的经验相当有限)

在我的库中,我释放了一个字符串。 (很神奇吧?)

这就是问题出现的地方。我有一个包含 char* 的结构,它可能分配在堆上,也可能不分配。虽然它是一个有效的指针,但它不能被释放。

IE

char* s1 = "A String";
char* s2 = (char*)memcpy(malloc(9), s1, 9);

free(s2);
free(s1);

将导致“free(s1);”上的错误(正如它应该) 因为 s1 实际上并不 需要 被释放,(它不在堆上)我如何以“可接受”的方式处理这个问题? (在类似的主题上,“让它崩溃”的答案似乎并不合理 IMO)

由于结构体不是由库单独创建的,因此无法保证使用 memcpy 之类的东西可以正确复制字符串。

鉴于这是一个 Windows 库,我无需担心使用 ISO C 的东西或标准 C 函数。

【问题讨论】:

  • 最佳答案(恕我直言):使用不透明指针来保证 struct 仅在库中创建。 (如果我使用 Windows,我会提供更多帮助。对不起。+1。)
  • 谢谢,如果最坏的情况发生,我可以这样做或使用 SEH(尽管后者会让我觉得我做错了什么)
  • 鉴于这是一个 Windows 库,请将参数设为 BSTR。然后您要求用户正确分配它(使用SysAllocString),并保证您使用匹配的释放器。其他方法只是......不好。如果您的用户有不同的编译器,那么即使他们确实使用了malloc,您也不能free() 字符串
  • 在释放字符串之前,我将在字符串上使用 (gasp) IsBadWritePtr...如果它是字符串文字,它将返回 true,并且我不会尝试释放字符串。

标签: c++ memory pointers free


【解决方案1】:

在 C++ 中,您根本不必担心这一点。使用std::string 并让它自动为您管理内存。 Don't manage memory manually.

如果您要手动执行此操作,则需要自己管理资源,通过

  • 让库的用户自己管理内存,或者
  • 要求用户告诉你如何管理内存,或者
  • 告诉用户您将如何管理内存,然后期望用户遵守。

【讨论】:

  • 根据 cmets 的说法,这是一个很好的建议,除了它是 (1) Windows 上的库 (2) 和 (3) 显然是预编译的。并且std::string 被确定为不安全地通过 Windows 上的模块边界。遵循 Win32 API 的模式,您给出的第一个项目符号是迄今为止 Windows 库处理内存的首选方式。
  • @Ben:Windows 编程:不是我的强项(我想这很有趣)。当然,您是对的:如果您无法控制库和任何针对它的链接的构建过程,那么这将是一个很大的问题。如果您将其发布为答案,我会支持您的 BSTR 解决方案。这是最合理的解决方案,IMO。
【解决方案2】:

鉴于这是一个 Windows 库,请将参数设为 BSTR。然后你要求用户正确分配它(使用SysAllocString)并且你保证使用a matching deallocator

其他方法只是……不好。如果您的用户有不同的编译器,那么即使他们确实使用了malloc,您也不能free() 字符串。

[注意:根据 James 的要求转换为评论,这实际上只是 his suggestions 的最后一个特定于 Windows 的案例]

进一步说明:BSTR 是 Unicode。我有点记得看到了一种使用 BSTR 分配器存储 ANSI 字符串的方法,似乎 SysAllocStringByteLen 这样做了,但请注意,将 ANSI 数据放入 BSTR 对任何熟悉 BSTR 的人来说都是非常违反直觉的。

【讨论】:

  • 好吧,但我似乎记得在处理来自本机 C++ 的 .NET 代码时,我需要使用 bstr(和 SAFEARRAY)时遇到过一些不好的经历。虽然这是题外话,但我会试一试。
  • @James:我怀疑是 COM 代码造成了困难,而不是 BSTR。 BSTR 函数实际上非常简单且易于从 C 或 C++ 中使用。我认为 VC++ 甚至提供了一个包装类来在 BSTR 超出范围时自动释放它,但它并没有添加太多功能并且不知道它是如何工作的让我很困扰,所以我总是打电话给 SysAllocString 和 @987654330直接@。
【解决方案3】:

您可以 malloc char *s1 并将 "A String" 作为值。之后,您可以免费s1

【讨论】:

  • 我知道,但是如果有人去 struct->val = "random";然后我又遇到问题了
【解决方案4】:

这是在编译时就知道的事情。您查看代码并知道什么可以免费,什么不能。所以不要想办法把它推迟到运行时,因为除了在这种情况下你找不到办法之外,这是在 C++ 中做事的错误方式。当你可以静态地做时,就静态地做。

使用类型系统。使用 RAII。

【讨论】:

  • 问题是它在 my 编译时并不知道,只有实际调用我的库的人才能知道。指针只是一个数字。
  • @James 这是关于所有权。要问的问题是谁拥有指针。这是您在函数文档中所说的内容。无论哪种方式,调用者都不应该检查它是否应该释放指针。同样,这是您需要明确的静态信息。
【解决方案5】:

将所有字符串存储在堆中,然后您就会知道它们都需要被释放。如果字符串存在于全局内存中,则将其复制到堆缓冲区中。

【讨论】:

  • 谁的堆?在 Windows 上,每个库都倾向于获得自己不兼容的 malloc/free 堆。 Win32 API 函数 HeapAllocHeapFree 跨模块边界工作,但它们与 CRT 提供的 malloc 不兼容,并且在任何模块中都是免费的。
  • malloc() 使用的堆,根据 OP 如何分配存储在堆上的字符串。
【解决方案6】:

我过去做过类似的事情,在某些情况下我会使用堆栈分配的字符串,而在其他情况下会使用堆分配的字符串,但它们最终会传递给其他一些通用代码。

在这种情况下,我所做的是有两个指针。一个是 NULL,或者是堆分配的字符串。另一个指针指向堆栈分配的内存或与前者相同的堆分配内存。当你去做你的 free() 时,你只检查前一个指针。

当然,这在暴露的 API 中看起来很糟糕。就我而言,它只是内部代码。

【讨论】:

    【解决方案7】:

    对于涉及 C++ 中内存分配的事情,智能指针非常棒。只是说说而已。

    http://www.cplusplus.com/reference/std/memory/auto_ptr/

    http://www.boost.org/doc/libs/1_45_0/libs/smart_ptr/smart_ptr.htm

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-11
      • 1970-01-01
      • 2012-01-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多