【问题标题】:C++: is push_back(new Object()) a memory leak?C++:push_back(new Object()) 是内存泄漏吗?
【发布时间】:2011-05-15 08:12:51
【问题描述】:

以下 C++ 代码是否存在内存泄漏?

list.push_back(new String("hi"));

据我了解,任何 std 集合/容器中的 push_back 总是会制作副本。因此,如果复制了新字符串,则没有什么可以删除新字符串,对吧?因为 push_back 之后没有引用它...

我是对还是错?

谢谢。

Jbu

编辑:我想我错了,因为 new 将返回一个指针......我们将始终拥有能够删除新字符串的指针

【问题讨论】:

  • 取决于list的定义。
  • 取决于list 是什么。假设它是std::list<String*>,@UncleBens 是正确的:大部分时间仍然可以正确清理。但是您必须手动进行清理; std::list 不会为你做的。
  • 是的。因为变量“list”实际上是一种类型,它有一个名为“push_back”的函数,其主体为空。

标签: c++ memory new-operator memory-leaks


【解决方案1】:

没有。

您可以通过以下方式删除对象:

delete list[i];
list.erase(list.begin() + i);

或通过以下方式清除整个列表:

for (unsigned int i = 0; i < list.size(); ++i)
{
  delete list[i];
}
list.clear();

【讨论】:

    【解决方案2】:

    是的,但不是你想的那样。

    根据list 的定义和初始化方式,push_back 可能会引发异常。如果是这样,则从new 返回的指针将丢失,并且永远无法释放。

    但是假设push_back成功返回,它存储了new返回的指针的副本,所以我们可以稍后通过在该副本上调用delete来释放内存,所以只要你没有内存泄漏正确地调用delete

    【讨论】:

    • 对不起,我不知道是指针被复制还是指向的数据也被复制了?例如:- String *str = new String("HI"); list.push_back(str);现在我可以调用 delete str 并且仍然能够从列表中访问“HI”,因为 valgrind 在 list.push_back 处显示泄漏而没有任何删除调用。
    【解决方案3】:
    list.push_back(new String("hi"));
    

    为什么首先要分配动态字符串?除非您想通过更改字符串在程序的不同部分之间进行通信(这很不寻常),否则请摆脱指针:

    std::list<std::string> list;         // note: no pointer!
    list.push_back(std::string("hi"));   // explicitly create temporary
    list.push_back("hi");                // alternative: rely on coercion
    

    【讨论】:

      【解决方案4】:

      是的,这是内存泄漏,除非您采取措施删除包含的指针。

      实现这一点的最佳方法是使用智能指针。比如Boost的shared_ptr或者C++0x的shared_ptr。

      【讨论】:

      • scaled_ptr??你是说 shared_ptr 吗?
      • 我认为你的意思是scoped_ptr,但它在容器中不起作用,因为它是不可复制的。
      • @Fred:这可能是 Boost 的未来版本 :)
      【解决方案5】:

      如果我看到这段代码,我会非常怀疑可能存在内存泄漏。从表面上看,它似乎是将分配的String* 添加到list&lt;String*&gt; 中。以我的经验,这通常伴随着错误的错误处理代码,它不能正确释放分配的内存。

      虽然在许多情况下这很危险,但不一定是内存泄漏。考虑以下示例:

      class Container {
        ~Container() {
          std::list<String*>::iterator it = list.begin();
          while (it != list.end()) {
            delete *it;
            it++;
          }
        }
      
        void SomeMethod() {
          ...
          list.push_back(new String("hi"));
        }
      
        std::list<String*> list;
      }
      

      在这段代码中没有泄漏,因为包含类负责分配的内存并将在析构函数中释放它。

      编辑

      正如 aschepler 指出的,如果 push_back 方法抛出异常,仍然存在泄漏。

      【讨论】:

      • 如果对push_back的调用抛出异常,这仍然是一个泄漏。
      • 除非声明复制构造函数和复制赋值操作符,否则还有双重删除的风险。
      【解决方案6】:

      你是对的,只要从列表中删除字符串时没有任何内容会删除它。

      【讨论】:

        【解决方案7】:

        不,向量存储指针,副本由指针组成。您可以在以后随时删除该对象。

        (如果语句碰巧抛出异常并且您没有正确捕获和处理它,您可能会发生泄漏。这就是您可能考虑使用智能指针的原因。)

        【讨论】:

        • “如果语句碰巧抛出了异常,而你没有正确地捕捉和处理它”——在这个语句的情况下,真的没有办法正确地处理它。如果push_back 抛出,那么它没有存储指针,并且没有办法释放它,因为这个调用代码也没有指针。我想理论上你可以用String::operator new 做点什么,但这听起来并不有趣。
        猜你喜欢
        • 1970-01-01
        • 2013-03-01
        • 1970-01-01
        • 2014-11-29
        • 1970-01-01
        • 1970-01-01
        • 2017-12-13
        • 2013-04-18
        相关资源
        最近更新 更多