【问题标题】:Should a void* pointer passed in by a callback be deleted回调传入的 void* 指针是否应该被删除
【发布时间】:2013-12-23 08:22:57
【问题描述】:

当第三方 API 将函数指针定义为带有 void* 的回调时,如下所示:

typedef void (__stdcall *CALLBACK)(int type,void * data);

然后回调实现通过函数调用传递给api,如下所示:

int __stdcall SetCallbackToGetAsyncStuff(CALLBACK func);

然后当事情发生时,API 会调用CALLBACK 的实现。

清理void*指针是不是实现方法的责任。 还是一般假设指针会被调用代码清除? 如果您通过enum, 类型知道大小,将void* 的内容复制到您自己的堆栈变量中是否明智? 如果除了头文件中的上述信息之外没有文档,应该假设什么。

【问题讨论】:

  • 在防守端,您应该假设void * data 不会永远存在,并且至少可以将内存用于其他用途。
  • 这个“谁拥有它”的问题是 C++ 试图摆脱指针传递并使用移动语义来有效地按值传递的原因。
  • 请注意,如果您尝试在 C++ 中的指针上使用operator delete如果对象是具有析构函数的类,它将不会调用析构函数
  • C 和 C++ 是不同的语言。 C 将类型枚举和 void* 指针与 malloc/free 一起使用。 C++ 使用继承和新/删除。弄清楚您使用的语言将有助于提出更连贯的问题。
  • 以上,加上检查库是否提供任何其他功能,允许您在完成它指向的数据后返回 void*。如果没有明确定义回调返回的数据的所有权/生命周期,则 lib 的文档非常糟糕。

标签: c++ c pointers memory-management


【解决方案1】:

“谁需要删除指针”这个问题的正确答案是“分配它的同一方”。如果一个库不是用您的代码编译的并且驻留在 .dll 文件中,它通常使用不同的 CRT。您不能用一个 CRT 创建对象并用另一个删除它。

第 3 方库可能依赖于您的应用分配的内存缓冲区,或者它可以自行分配内存并为您的应用提供对其的访问权限。如果您没有分配与传递给回调的数据相关的任何内存,则不应删除它。至少在使用设计良好的库时。

从你的问题中很难看出是谁分配了内存。

【讨论】:

  • 如果通过 LoadLibrary 调用将 dll 加载到我的程序中会怎样。还是不同的 CRT?
  • 是的,当然。不管它是如何加载的。只关心它是如何构建的。请注意,事实上它可以使用相同的 CRT,但一般它不会。
  • 谢谢您的帮助,先生
  • 如上面评论中所述,删除 void* 指针甚至不会调用析构函数。除了 DLL 问题之外,删除您不熟悉的内容从根本上来说是糟糕的设计。
【解决方案2】:

如何定义回调取决于客户端代码。如果回调函数承担所有权,那么它应该释放。

请注意同一数据指针可能被传递给多个回调并导致程序未定义行为的其他情况。

或者您可以保留其创建者的所有权。

【讨论】:

  • 对象的创建者假定所有权属于客户。
猜你喜欢
  • 2012-09-27
  • 1970-01-01
  • 2015-11-27
  • 2018-08-27
  • 2017-09-10
  • 1970-01-01
  • 2013-10-10
  • 2011-09-04
  • 1970-01-01
相关资源
最近更新 更多