【问题标题】:Will using shared_ptr for returning pointers from a method always save me from memory leaks?使用 shared_ptr 从方法返回指针总是可以避免内存泄漏吗?
【发布时间】:2012-02-05 17:38:34
【问题描述】:

我是一个 c++ 新手,我的代码目前在多个地方都是新的,没有调用 delete。我知道我需要为此做点什么。

我的典型用法是在另一个类成员方法中新建一个类实例,然后该方法返回指向该对象的指针。

如果我将返回类型从 MyType* 更改为 std::tr1::shared_ptr 是否会修复我的代码不泄漏内存?

非常感谢。

编辑: 同样,我目前将新的对象存储为 MyType* 作为 std:map 中的值。此映射是类实例的私有成员。如果我只是将其更改为 std::tr1::shared_ptr 是否会在其所有者(类)超出范围时清除这些?

再次感谢

【问题讨论】:

  • 如果您一直在编写代码而不关心内存管理,那么您可能会遇到比泄漏更大的问题。
  • 这是我第一个周末写 c++ - 给我一点余地。
  • 也许显示一个示例,说明您将在何处使用shared_pointer?很有可能它对你的用途来说有点过头了。

标签: c++


【解决方案1】:

这是一个合理的创可贴,当然。

共享指针是一个引用计数的指针。因此,只要存在一个或多个 shared_ptrs 指向一个对象,该对象就会保持活动状态。如果您有循环引用,则会出现问题。那么引用计数永远不会达到 0,对象也永远不会被删除。

所以shared_ptr * 仍然* 要求您了解自己在做什么并考虑对象所有权,就像您在 C++ 中一直必须做的那样。但它简化了一些原本复杂的场景,在这些场景中很难确定所有权。

真正解决您的问题的方法是:

  • 尽量减少使用new 分配的数量。可以将对象存储在堆栈中吗?是否可以将对象重写为 RAII 类,以便在堆栈(或具有自动存储持续时间的其他地方)上分配一个小的包装对象,并通过其构造函数和析构函数管理堆分配的内存资源?然后,只要该对象存在,它分配的内存就会被保留,一旦它被销毁,它就会删除它分配的内存。
  • 当您使用new 分配对象时,将它们放在其中一个 智能指针类中。 shared_ptr 很受欢迎,因为它最接近垃圾收集器,但事实并非如此,如果您将其视为垃圾收集器并以此为借口不考虑内存管理,那么它不会不工作。了解所有智能指针类(C++03 中的 scoped_ptr 和 auto_ptr,或替代 C++11 中的 unique_ptr、shared_ptr 和 weak_ptr),并使用最适合您的场景的类。李>
  • 考虑所有权。每次分配内存时,都需要确定所有者,其生命周期将控制内存分配的生命周期。考虑一下您的分配需要多长时间的生命周期,并在调用其析构函数时拥有另一个对象(其生命周期是自动管理的,可能是因为它在堆栈上)delete 您的内存。

没有快速简便的解决方法。在 C++ 中处理内存管理的方法是避免内存管理。将其委托给您的对象。如果您在自己的代码中调用delete,那么您做错了。通常,您甚至不需要new,但如果您需要,请立即将所有权分配给智能指针,并让它为您调用delete

根据经验,除非您是库编写者,否则不应编写 newdelete。您几乎不应该使用原始指针,只有在绝对必要时才使用智能指针。让您的班级完成繁重的工作。不要害怕将它们放入堆栈,按值传递它们,并让它们在内部处理它们的资源。

【讨论】:

  • @jalf:图书馆作者??请解释。我正在编写一个可重用的库。
  • @CodingQuant:嗯,*有人最终需要newdelete 内存块。但它通常可以隐藏在库中。例如,当您将对象插入标准库vector 时,它会在内部分配并释放该对象,而您永远不必调用newdelete。但是编写vector 类的图书馆作者不得不打电话给他们。因此,如果您正在编写库代码,您可能需要直接使用 new/delete,否则,通常最好留给库。您只需使用该库,它就可以完成内部需要做的事情
【解决方案2】:

如果您是 C++ 新手,则无论您是否使用 shared_ptr,您都需要了解和接受指针管理的几点。

在您使用 C++ 时,您很可能需要使用 new 并将其返回指针分配给您已声明的类指针。我认为最好花时间了解那里发生了什么,即使您编写了一个小型测试程序并观察构造函数在调试器中执行。

如果你使用像 std::string 这样的类,它的构造函数和析构函数将为你做字符串指针管理,但我相信了解该类的幕后发生的事情是个好主意,如果仅此而已阅读文档。

再举一个例子,你不能使用一些类,除非你对 API 进行大量的详细阅读,否则你会遇到问题。几年前,我曾在使用商业级套餐的公司工作。有人使用这个包的线程池类编写了一个多线程程序。

文档清楚地表明您不能只退出未完成的线程。然而,我看到程序的作者没有费心在退出时同步和关闭所有线程,并在他们的程序退出时抛出异常。这是关于商业金融产品的。

我的建议是不要从执行指针管理中获得拯救。有像 string 这样的 std 类可以减轻你的头痛,但除了你自己的勤奋和测试之外,没有什么能阻止问题。

【讨论】:

    【解决方案3】:

    只要您了解 tr1 共享指针的工作原理,就可以。

    还请查看 Boost C++ shared_ptr - 它可能是您想要的更多。

    【讨论】:

    • 1:为什么 Boost 的 shared_ptr 比 tr1std shared_ptr 更“想要”?以及 2 为什么暗示他需要了解共享指针的工作原理,而不是实际解释它
    • 无论你是否理解共享指针都可以解决问题,当你理解它们时它们不会神奇地开始工作;他们应该被理解,所以一些模糊的解释可能会有所帮助。也绝对没有理由建议 boost 的 shared_ptr 优于内置(现在大多数编译器都提供 TR1 或 C++11 智能指针)。
    • @peachykeen:不正确。 C++11 shared_ptr 或多或少等同于 Boost 的版本。但 TR1 是基于一个较旧的 Boost 实现,它没有那么多特性。 TR1 版本中缺少指针别名和各种其他技术。如果您无法访问 C++11 版本,请使用 Boost。
    • @NicolBolas 虽然您总体上是正确的,但我怀疑附加功能在这里是否很重要。尽管如此,还是有利于 OP 了解以供将来参考。是否有任何当前/最近的编译器不提供 C++11 版本的智能指针?
    猜你喜欢
    • 2010-12-22
    • 2013-09-23
    • 1970-01-01
    • 2011-01-13
    • 2017-10-31
    • 2017-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多