使用智能指针释放内存
Posted
技术标签:
【中文标题】使用智能指针释放内存【英文标题】:Memory deallocation with smart pointer 【发布时间】:2012-07-18 07:10:40 【问题描述】:在 C++ 中,假设 Helper 类中有一个方法,它返回一个指向另一个对象的指针。除了方法签名和返回对象的类型外,我没有关于此方法的更多信息。这种情况下怎么做内存管理?
我尝试在下面使用智能指针作为这个功能:
void f()
auto_ptr<SomeClass> p_someClass = p_Helper->getSomeclass();
p_someClass->doSomething();
一旦 f() 超出范围,分配给 p_someClass 的内存就会被释放。 但是,如果 getSomeclass() 不分配新内存而只是返回一个“单例”指针(并且 p_Helper 也是单例)怎么办?那么下一次调用 p_Helper->getSomeclass() 就会有麻烦了。
处理这个问题的常用方法是什么,尤其是当 Helper 类的文档很少时?
【问题讨论】:
除了请教作者、阅读文档或查看源代码之外别无他法。 Mb 函数返回对 auto_ptr 的引用,而不是对象? 如果它是一个单例,最好返回一个对对象的引用(或一个weak_ptr)以表明删除不是一个好主意。 【参考方案1】:帮助类的文档是怎么说的?那就是
终极问题。如果没有,您不能返回指针或引用
指定它的生命周期:如果它是一个指向内部事物的指针
类,它可能是类对象的生命周期,但它也可以
有静态生命周期(直到程序结束——这是
如果函数返回字符串文字为char const*
),它
可能有一些较短的生命周期(例如,由
operator[]
由标准库容器提供),或者助手可能
希望你删除它。后者应该是罕见的,然而,在纯
C++;在这种情况下,约定是返回std::auto_ptr
(或
std::unique_ptr
如果你有一个非常现代的编译器)。 (在 C 中,它是
经常记录返回的指针必须被释放
调用返回它的库中的特定函数。没有
析构函数,你必须做一些事情才能在最后重新获得控制权。)
在没有文档的情况下,我很想说这个库是 不可用。仍然......假设它指向内部的东西并且 拥有类的生命周期可能是最合理的猜测; 这是程序员最容易忘记记录的情况。 删除它,或将其放入将删除它的智能指针中,是 可能不是一个好主意:关于所有权问题已经说得够多了 班级作者似乎不太可能没有记录 事实上,如果你应该删除它。 (但请注意, 即使您不应该删除它,终生问题仍然存在。)
【讨论】:
不要发动一场火焰战争,但这正是我真正讨厌 C++ 的原因。不是每个人都是图书馆开发者。大多数时候,在企业系统世界中,人们在没有文档的情况下编写了糟糕的代码。然而,糟糕的文档从来都不是 Java 的真正问题——咆哮结束——:p @TommyQ 我不能同意你的看法。我在 Java 中遇到了糟糕或缺少文档的严重问题。问题与语言无关。 (即使关于对象的生命周期;在 Java 中很容易以“僵尸”对象结束,它们的生命周期已经结束,但对象仍然存在。)【参考方案2】:如果你不是 p_Helper 类的作者,首先:
单例通常没有公共析构函数,因此在这种情况下不会编译。
其次,如果您“只是得到”一个没有任何进一步信息的裸指针,则无法知道是否可以删除它。 需要在文档中提供该信息,以便您使用函数/方法。
如果您正在设计 p_Helper,那么让it 返回智能指针,而不是裸指针。如果该方法为每次调用创建一个新资源,我建议unique_ptr
,看看这里:Differences between unique_ptr and shared_ptr
【讨论】:
不幸的是,代码可以编译,文档只不过是方法签名本身。担心内存泄漏,我用智能指针包装了返回的原始指针,稍后会出现一些“违规 - 尝试从空闲内存区域读取”错误。 所以它建议返回的指针要么是单例的,要么甚至是指向其他静态数据的指针——在这两种情况下,当你执行自动删除时,你都会弄乱内存。或许可以试试 valgrind(linux 下)或者其他内存泄漏检测软件,在不删除的情况下看看是否有内存泄漏 好建议@zodi,否则联系作者或尝试阅读代码。 @zodi 我认为最有可能的是指针指向辅助对象中的一些内部数据。所以客户端代码不应该删除它。但这仍然没有解决生命周期的问题:例如,指针可能会通过调用辅助对象上的某些其他函数而无效。 (想想std::vector<>::data()
返回的指针。)【参考方案3】:
这种情况的典型方法是使用引用计数和像shared_ptr
这样的智能指针,它通常会处理所有合理的情况。
【讨论】:
在这种情况下,引用计数将不起作用,因为 Helper 类返回原始指针。我的问题更多是关于如何知道何时删除指针而不是使用哪个智能指针。 如果指针指向类中的内部数据(这是最合乎逻辑的默认假设),那将是灾难的根源。 @James Kanze:当然,内部数据必须是一个智能指针,然后才能分离动态分配的对象。 @sharptooth 为什么?我知道的任何实际情况都没有。 (std::vector<>::data()
、std::string::c_str()
等)在应用程序代码中,更常见的情况之一是返回指向映射中元素的指针(如果该元素不存在,则返回 NULL
)。为什么要坚持动态分配。
@JamesKanze:当然,在这些情况下,容器完全拥有存储的数据。【参考方案4】:
在这种情况下,您可以使用原始指针。
void f()
SomeClass *p_someClass = p_Helper->getSomeclass();
p_someClass->doSomething();
【讨论】:
p_Helper->getSomeclass().get(); 我认为“.get()”是行不通的。因为“返回给我一个指向另一个对象的指针”。我认为默认情况下它表示原始指针。 然后忘了要不要删除? @TommyQ 实际上你需要阅读这个类的文档来确定你是否需要释放内存。【参考方案5】:您可以做一个快速测试并比较两次调用 p_Helper->getSomeclass(); 所返回的指针;
bool do_not_delete = p_Helper->getSomeclass() == p_Helper->getSomeclass();
如果两个指针相等,您很可能会得到一个作为(可能是可选的)引用的指针。
hth 托斯滕
【讨论】:
这可能是他不应该删除的一个很好的迹象。但是,如果它们不相等,那就没什么好说的了。以上是关于使用智能指针释放内存的主要内容,如果未能解决你的问题,请参考以下文章