在boost::shared_ptr
之前,从函数返回堆分配指针被认为是一种不好的做法,因为调用者需要记住free()
该对象吗?
或者,它被认为是“正常”吗?
答案 0 :(得分:11)
我不认为这是不好的做法,只要您的API还提供等效的XXX_free
(或XXX_close
,XXX_clearup
或其他)功能,客户端代码就可以完成指针时调用。
这样,您就拥有了一致的对称API,从某种意义上说,堆对象的生命周期的责任保存在一个地方。
这种方法也适用于更复杂的资源释放。例如,如果返回的指针是动态分配的结构,而该结构又具有指向动态分配的内存的成员,则可以从客户端代码中隐藏/抽象整个清理过程。
答案 1 :(得分:2)
你已经标记了你的问题C.在C中,这是非常普遍的,例如fopen
返回FILE *
,必须稍后通过调用fclose
取消分配。
如果你打算用C ++标记它,那就更复杂了。较旧的代码库(20世纪90年代中期及更早版本)经常将裸指针传递给对象。整个商业支持的库基于该模式(Borland的OWL,Microsoft MFC)。
答案 2 :(得分:1)
如果您需要这样做,通常的做法是提供您自己的“免费”功能,该功能可以获取您分配的指针并将其释放。这可以防止用户使用会破坏内存的不兼容的免费实现。
答案 3 :(得分:1)
您将找到两种方法的示例:分配内存和返回指针的函数,或者接受指向已分配空间的指针的函数。
只要明确记录并遵循界面,两者都有正面和负面。例如,正如许多其他人所提到的,提供分配功能的库通常应该提供删除功能。正如您,客户端,不知道在该奇特函数中使用了什么方法来分配内存,您(客户端)不知道应该使用什么方法来销毁它。
另一方面,当您需要担心存储分配,将其传递给可能会或可能不会执行预期工作的内容时,逻辑可能会更复杂,然后确定该存储是否仍然相关,等等根据内存的 use ,隐藏分配细节可能有助于封装它的一些优化。
简短的回答是:这取决于你。真正错误的方法是选择一些东西,或者在界面中不一致或不清楚。
答案 4 :(得分:0)
它是,并且仍然很常见,因为它几乎是处理在某些操作系统上针对不同运行时构建的库的唯一方法。例如,在Windows上,在单个可执行文件中共享多个VC ++运行时库通常只有在库负责所有自己的内存管理时才能正常工作,包括对象的分配和处理。在这种情况下,shared_ptr
和类似工具实际上可能会导致问题。
话虽如此,通常情况下,功能名称和/或文档(如果正确完成)会明显发生这种情况。拥有相应的DeleteXXX()函数来处理免费通话也很常见。
答案 5 :(得分:0)
通常,您只会从显式create_blah()函数返回指针
更常见的是传入指针(指针),如果它是null,则由函数分配。
答案 6 :(得分:0)
实际上,一个更好的习惯用法(由COM接口使用)是要求在函数调用点之前在调用者处创建指针,并编写一个接受双指针的函数。
HRESULT CreateDevice( [in] UINT Adapter, [in] D3DDEVTYPE DeviceType, [in] HWND hFocusWindow, [in] DWORD BehaviorFlags, [in, out] D3DPRESENT_PARAMETERS *pPresentationParameters, [out, retval] IDirect3DDevice9 **ppReturnedDeviceInterface );
因此,调用者负责创建指针并调用分配函数,因此更有可能记得调用deallocation函数(在COM的情况下需要在COM对象上调用->Release()
方法)
但我认为采用创建/销毁函数,结合传递双指针,是一种更好的方法来提醒收件人在使用对象后清理堆分配的对象。
我同意Oli创建/销毁函数更加对称,并且 Destroy函数的存在应该将API用户转变为他从Create获得这些对象的事实函数不仅会自行消失,而且需要调用它们(Destroy fcns)。