【问题标题】:deleting element (objects) within a vector (not referenced by pointer) , memory handling删除向量中的元素(对象)(不被指针引用),内存处理
【发布时间】:2010-02-10 11:37:04
【问题描述】:

这是this question 的扩展。我在网上搜索过,但找不到满意的答案。

我有一个class A,它定义了一个包含多个class Region 实例的向量。这些Region 实例的内存处理需要由Class A 管理

我的问题是:

1.在下面的sn-p代码中,是否需要在A类的析构函数中显式删除这些实例?

2. 我应该将实例创建为 new Region(i) 吗?是否比第一个选项更好(不使用new)A 类是一个相当大的对象。我应该如何确定是否使用新的?

3. 如果对#2 的回答是肯定的,我应该如何在析构函数中删除这些实例? delete Region(i)(在 for 循环中)或 delete [] reg??我猜以前的方法是正确的方法,但想确认一下。

4. 除了“Region instances are not deleted”之外,你有没有看到明显的内存泄漏……尤其是在A的构造函数中构造Region对象?

class Region{
   public:
      Region(int num);
      int number;
      std::vector <elemt*> elements;   
      int info;
}

class A{
public:
    std::vector<Region> reg;
    const int numOfRegions = 100;
}

A::A(){
    int i;
    for ( i=0; i<numOfRegions; i++){
        reg.push_back(Region(i));
      } 
}

A::~A(){
  // How should the elements within vector Region be deleted??
  // Should I use "new" to allocate memory to instances of Region()
}

更新: 非常感谢所有回答的人!

【问题讨论】:

    标签: c++


    【解决方案1】:

    在下面的代码sn-p中,是否需要显式删除这些 类的析构函数中的实例 一个?

    不 - 它们将自动为您删除 - 如果您不使用 new 创建它,则不要删除它。

    我应该将实例创建为 new Region(i) 吗?是不是更好 第一个选项(不使用新的)A 类 是一个相当大的物体。我该怎么办 判断是否使用new?

    A 的大小不是问题。这个问题没有明确的答案,但一般规则是,如果您不必使用 new 动态创建对象,则不要这样做。

    如果对 #2 的回答是肯定的,我应该如何在 析构函数?删除 Region(i)(在 for 循环)或删除 [] reg??我是 猜测前一种方式是正确的 方式,但想确认。

    如果您使用 new 创建它们,您将在 for 循环中删除它们:

     delete reg[i];
    

    reg 当然必须是指针向量。更好的选择是使用智能指针向量。

    除了 "Region instances are not deleted" 之外,你有没有看到任何明显的 内存泄漏..尤其是在 在 A 中构建 Region 对象 构造函数?

    它们已被删除 - 只是不是由您删除。这被称为 RAII,是非常非常好的 C++ 实践 - 您应该尽可能使用 RAII。

    【讨论】:

    • @Neil:很好的答案。你们非常乐于助人(并且总是在那里寻求帮助)。我只是有一个小疑问,在上面的代码中,我说明了 Region 实例是在 A 类的构造函数中添加的。但是,如果我要在运行时通过调用 A 类的方法来填充这个列表: :addRegions(int num) ,在这种情况下我应该使用“new”吗?还是我应该坚持使用我当前的代码?
    • @memC:它的向量决定了你应该如何向它添加项目。如果在构造函数中你这样做:reg.push_back(Region(i)),那么你需要在像A::addRegions(int num); 这样的方法中使用类似的东西。所以我说还是不要使用new
    • @memC 您可以在构建时或之后进行。当然,您必须提供一个成员函数来执行此操作。无论哪种情况,都无需使用 new 创建对象。
    【解决方案2】:
    1. 没有。 std::vectorRegions 存储为对象,并在添加/删除/覆盖元素时调用必要的(反)构造函数。

    2. 没有。仅当您将向量声明为std::vector&lt;Region *&gt; reg; 时。如果 Region 是多态的或者复制/赋值构造函数很昂贵(向量经常复制元素),则必须这样做。

    3. 如果将它们存储为指针,则需要遍历 reg 并使用 delete ptr; 删除每个元素。

    4. 根据您创建elemt 类实例的方式,您可能需要向Region 添加一个析构函数来销毁这些实例。

    【讨论】:

    • +1,但请编辑您的答案以将解构函数更改为析构函数。
    • 谢谢ebo...您所有的答案都非常有用。请看我对尼尔回答的回复..
    【解决方案3】:

    class A 内,一切似乎都定义好了。 (您需要整理类声明)。这意味着当 A 的实例被销毁时,所有内容都将自动销毁。是的,我的意思是 std::vector reg; 会销毁自己,以及它负责的所有 Region 实例的副本。

    您真的在询问class Region 及其具有指针的vector,尽管您没有显示任何代码,但可能需要删除其指针?

    编辑:

    (第一次编辑包含Region的详细信息,第二次编辑删除它们并添加A::addRegions)

    我想这就是你所追求的:

    #include <vector>
    
    class Region{
       public:
          Region(int num);
          // Details of Region removed
    };
    
    class A{
        std::vector<Region> reg;
        const int numOfRegions;
    public:
        A();
        // No destructor needed: ~A();
        void addRegions(int num);
    };
    
    A::A():numOfRegions(100){
        for (int i=0; i<numOfRegions; ++i){
            reg.push_back(Region(i));
          } 
    }
    void A::addRegions(int num)
    {
        for (int i=0; i<num; ++i){
             reg.push_back(Region(i));
        } 
    }
    

    注意class A 没有析构函数。

    A::addRegions 也使用push_back,即使现在也不需要析构函数。

    还要注意类声明后面有分号,A 的构造函数初始化numOfRegions

    【讨论】:

    • 不,我不是询问类 Region 及其向量。你的答案就是我所需要的......但是,现在我很困惑是应该使用“新”还是保持代码的原样。 (因为@MSalters 评论而感到困惑)谁应该处理 Region 对象的删除?使用“新”是更好的做法吗?如果是这样,我是否也应该删除 ~A()... 中的那些,或者它会由向量本身处理?
    • 您所指出的最佳做法是让std::vector 负责管理Region 实例的内存。
    • 是的,我明白了.. 谢谢!您能否回答这个问题(在 Neeils 回复的评论中添加):“在这个例子中,我说明了 Region 实例是在类 A 的构造函数中添加的。但是,如果我要填充这个列表,在运行时时间,通过调用类 A::addRegions(int num) 上的方法,在这种情况下我应该使用“new”吗?还是应该坚持使用我当前的代码?”
    【解决方案4】:

    1. 在您的示例中,您唯一需要在此处显式删除的是 elemt*(如果它们是动态分配的)。如果是这样,它们必须由拥有它们的人删除。如果您的 Region 仅指向它们,则不应在其析构函数中删除它们。

    2. 首先,您的向量在堆栈中分配,并且将毫无问题地被释放。其次,对于您使用new Region(i),您需要更改您的class A 声明。但在你的情况下没有必要这样做。应该使用 operator new 的几个示例:
    1) 需要更持久的数据,因为您的动态分配的数据将持续存在,直到显式解除分配(并且只要您保持一个指向它的指针)
    2)您的对象可能太大而无法全部存储在堆栈中。

    3.如果你确实使用了new Region(i),你会在某个时候使用operator delete,可能在析构函数或其他清理函数上,以正确释放它。

    4. 例如,仅当您直接在 elements 向量(即 elements.push_back(new elemt()))中创建新的 elemt 时,您的构造函数才会出现问题。这是一种危险的设计,可能会导致多次内存泄漏或段错误风险。如果您想以这种方式分配它们,则需要一个支持复制机制的智能指针,例如 shared pointer

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-12-10
      • 2022-01-07
      • 2014-04-28
      • 1970-01-01
      • 1970-01-01
      • 2014-05-05
      • 2019-12-02
      相关资源
      最近更新 更多