【问题标题】:When to use "delete"?何时使用“删除”?
【发布时间】:2012-04-10 22:09:38
【问题描述】:

我想在objList 中存储10 个Obj 对象,但我不知道在这种情况下何时使用delete 是合适的。如果我在下面代码中注释的行中使用delete Obj;Obj 是否仍会存储在objList 中?

struct Obj {
    int u;
    int v;
};

vector<Obj> objList;

int main() {
    for(int i = 0; i < 10; i++) {
        Obj *obj = new Obj();
        obj->u = i;
        obj->v = i + 1;
        objList.push_back(*obj);
        // Should i use "delete Obj;" here? 
    }
}

【问题讨论】:

  • new 在这里根本不需要。使用Obj obj; 在堆栈上创建对象。
  • 即使你确实需要new,那么一个简单的delete 也不够——如果push_back 抛出,那么你就有了泄漏。您应该始终使用smart pointers 或其他RAII 对象来管理动态资源。

标签: c++ memory-management


【解决方案1】:

您使用new 在堆上创建的任何对象都需要由delete 清除。在您的代码中,您实际上是在集合中存储一个副本。

objList.push_back(*Obj);

这行一步一步做的是:

  1. 间接指向Obj占用的底层堆内存(返回对象Obj
  2. 调用复制构造函数来创建临时副本
  3. 将临时副本存储在集合中

您不需要在堆上创建这个初始 Obj,正如@Luchian Grigore 所指出的那样,本地分配的堆栈就足够了。

Obj obj;
objList.push_back(obj);

您不需要对集合中的副本调用 delete,当您删除元素时,STL 集合将自己处理这块内存,但您仍然需要删除原始堆分配的对象。

如果你用std::shared_ptr存储你的对象会更好。这样,当所有对 Obj 的引用都被删除时,将调用 delete。

std::vector< std::shared_ptr< Obj > > vec;
vec.push_back( std::make_shared( new Obj() ) );

【讨论】:

  • 我试图指出集合分配的堆空间中对象的生命周期不必由 OP 管理。 :-)
  • 还有,不是栈和堆,而是自动动态存储。
  • @Konrad,你的意思是当我使用objList.push_back(*obj); 时,我们将*obj 的“副本”存储在objList 中。所以我们不必担心删除obj。我的理解对吗?
  • @Mr.mr.:你的理解是错误的:在你的代码中,你“新建”了一个obj指向的Obj,所以你必须删除它。您不必担心该 Obj 对象的副本。
【解决方案2】:

是的,你应该这样做。

程序中的每个new 都应该有一个对应的delete

但是你的程序不需要动态分配:

Obj obj;
obj.u = i;
obj.v = i + 1;
objList.push_back(obj);

另外,您的语法错误 - objList.push_back(*Obj); // should be *obj, not *Obj

【讨论】:

    【解决方案3】:

    想想会发生什么:

    在您的循环中,您创建一个新的 Obj 实例并为其分配一些值。这个实例是在你的堆上创建的——因此你必须在之后释放它。当您将实例添加到向量时,您会隐含地创建它的副本 - 因为您有一个对象向量,而不是指针。因此,vector 保留了自己的 Obj 副本。您可以安全地删除您的 Obj 实例。

    顺便说一句:

    • 您甚至可以重用对象实例并在循环之外创建和释放它
    • 不需要在堆上分配 Obj 实例

    对象 x; x.u =我; x.v = i+1; objList.push_back(x);

    也可以

    您应该阅读一些关于智能指针和智能指针容器的文章。例如。 boost::scoped_ptr,boost::shared_ptr,std::auto_ptr。使用这些范例通常不需要自己调用 delete。

    【讨论】:

      【解决方案4】:

      你想使用堆,所以我建议将你的向量声明更改为指针向量,像这样。

      vector<Obj *>objList;
      

      为什么?因为如果它是 Obj 的向量,那么您存储的内容实际上是您创建的指针的值 Obj 的副本。 objList 的项目和你创建的 obj 指针是完全分开的,不相关的! 所以当你,

      delete obj
      

      objList 上的东西在任何方面都完全不受影响
      此外,vector&lt;Obj&gt;(无星号)将其项目存储为 Obj,并且它们在 stack 上,当您的程序超出范围时它们将消失!

      【讨论】:

        【解决方案5】:

        嗯,简单的规则是new 构造的每个变量都应该由delete 清理。

        但是,根据您的目标,您可能不需要自己写 delete

        在家里,当你学习内存管理的血腥细节时,你可能会写很多delete,就像你写new一样。

        然而,专业人士绝不会在应用代码 (*) 中使用 deletedelete 是一种代码味道。这是在存在异常时内存泄漏的最短方法。专业人士使用 RAII 安全地处理异常,即:智能指针/智能容器。

        (*) 与库代码相反,即有人一天写了shared_ptr 类。

        【讨论】:

          猜你喜欢
          • 2016-03-27
          • 2016-06-14
          • 1970-01-01
          • 1970-01-01
          • 2012-05-03
          • 2013-06-09
          • 1970-01-01
          • 2018-11-04
          • 2018-05-21
          相关资源
          最近更新 更多