【问题标题】:How do I deallocate contents of a vector upon its destruction?如何在销毁向量时释放其内容?
【发布时间】:2013-07-29 13:43:12
【问题描述】:

据我所知,对于这两个向量声明:

//TYPE 1
std::vector<cls> vec;     //cls is user defined datatype(A class)

vector 的内存在栈上分配,vector 中内容的内存在堆上分配。

以下声明也是如此(如果我错了,请纠正我):

//TYPE 2
std::vector<cls*> vec;    //cls is user defined datatype(A class)

现在,当类型 1 中的向量超出范围时,将为存储在其中的对象释放内存。

但是如果我插入如下元素(假设我有适当的重载构造函数)然后向量超出范围,那么类型 2 会发生什么:

vec.push_back(new cls(5));

我明确尝试调用 clear 但未调用析构函数。是否会自动释放内存并调用析构函数。如果没有,那么如何实现。

另外,如果我将向量声明为:为向量分配的内存以及内容在哪里:

std::vector<cls*> *vec = new std::vector<cls*>;

【问题讨论】:

  • "会自动释放内存并调用析构函数吗?" - 不。只有用于存储指针的内存。 “如何做到这一点?” - 明确释放它,使用智能指针或只使用第一种形式。它是一个容器,让它包含对象。
  • 在 C++ 中,我们通常不使用术语堆栈,而是使用自动存储了解更多信息,请参阅:stackoverflow.com/questions/6500313/…
  • 一般规则:不要在 std 集合中使用原始指针。它们不会被自动清理,因此您很容易遇到内存泄漏。改用 shared_ptr,它在 boost 中可用。

标签: c++ stl


【解决方案1】:

这就是我们有智能指针的原因。

{
    std::vector<std::unique_ptr<cls>> vec;

    // C++14 will allow std::make_unique
    vec.emplace_back(std::unique_ptr<cls>(new cls(5)));
}

当向量超出范围时,unique_ptrs 的析构函数将被调用并释放内存。

在您的情况下,使用原始指针,您必须手动使用 delete 创建 new

// Something along the lines of this.
for (auto&& elem : vec) {
    delete elem;
}

另外,如果我将向量声明为:为向量分配的内存以及内容在哪里:

您使用new 分配向量,所以它会在堆上。

【讨论】:

  • 能否请您包含 sn-p 以显式删除对象?
  • @Saksham 不要明确删除对象。
  • @Saksham 我提供了一个示例,但您可能希望坚持让 RAII 为您管理内存。只使用智能指针的向量要好得多,因为在发生异常的情况下,它们会超出范围,并且不会出现内存泄漏 ^^。使用原始指针,您有更多的负担需要管理
  • @BartekBanachewicz 好的。我会注意不要那样删除。我只是在清理我的概念。谢谢!
【解决方案2】:

但是如果我插入如下元素,类型 2 会发生什么(假设 我有正确的重载构造函数)然后向量熄灭 范围:

内存会泄漏 - 您需要单独迭代向量和 delete 每个元素。

【讨论】:

  • 能否请您包含 sn-p 以显式删除对象?
  • for (vector::iterator it = vec.begin(); it != vec.end(); ++it) delete *it;
  • Saksham,如果你花时间学习不需要你显式删除对象的智能指针,你会写出更好的代码。
  • 我正在尝试通过索引访问矢量元素作为 delete *vec[0]。不可能吗?
  • 是的,但是你不需要 * 因为它已经返回了指针,你只能在指针上调用 delete,而不是取消引用的对象。
【解决方案3】:

如果您将指向对象的指针存储在向量中,则需要在销毁向量之前删除元素(或有内存泄漏,但这不是一件好事)。但是你不应该使用“原始”指针。例如,如果您使用unique_ptr&lt;cls&gt; 而不是*cls,问题就解决了。

所以而不是:

vec.push_back(new cls(5))

使用

vec.push_back(unique_ptr(new cls(5)))

vec.push_back(make_unique<cls>(5))

而且您不必担心找到一些地方来迭代向量并删除内容。

new vector&lt;...&gt; 是“正确”的情况很少。如果您这样做,请考虑是否真的有必要。

【讨论】:

  • @BartekBanachewicz:谢谢,已修改。
  • 这显然是委员会的错,而不是开发者。
【解决方案4】:

不适合这种类型,您可以通过 vec.push_back (new cls) 推回一个新的 cls 字节

//TYPE 2
vector<cls*> vec;    //cls is user defined datatype(A class)

然而,vector 会清理指针变量的内存,但不会清理它们指向的实例,你必须在 vec 中的每个 cls* 上运行 delete。否则你有内存泄漏。

【讨论】:

    【解决方案5】:

    如果对象是动态分配的,std::vector 将不会 delete 存储其中的对象。你必须自己这样做。最好完全避免使用原始内存——通常您希望将指针包装在std::shared_ptrstd::unique_ptr 中。它们都会自动为您释放内存。

    不要使用new 创建vector

    【讨论】:

    • 使用new创建vector并没有错,只要指向它的指针也被管理。
    • @BartekBanachewicz 除了您(几乎)不需要这样做之外,没有什么错。
    【解决方案6】:

    vector 的内存不一定是在栈上分配的。正如您在上一个 sn-p 中所展示的,向量的内存可以从堆中分配。

    当向量超出堆栈范围时,或者当向量在堆上使用 new 分配时使用 delete 销毁,它将自动销毁其所有元素。但是,常规指针没有析构函数,并且在它们死亡时不会对它们指向的对象做任何特殊的事情。因此,尽管清除指针向量会破坏指针,但它们指向的对象不会被破坏。

    有两种解决方案。在清除向量之前,遍历向量中的每个指针并对其调用 delete。更好的解决方案是使用智能指针,例如 unique_ptr。当一个unique_ptr被销毁时,它指向的对象会被自动删除。

    所以用一个

    vector<unique_ptr<cls>>
    

    ,你可以像往常一样推回新的cls,当vector被销毁时,你通过unique_ptr插入vector中的所有cls对象也会被销毁。

    【讨论】:

      【解决方案7】:

      持有指针的向量不负责指针指向的内存。 当向量超出范围时,它将释放它为指针所拥有的内存,而不是这些指针所指向的内存

      管理这段记忆仍然是你的责任。这就是为什么您应该将智能指针用作std::unique_ptrstd::shared_ptr 以避免内存泄漏(如果您忘记手动删除可能会发生这种情况)。

      另外,如果我将向量声明为:为向量分配的内存以及内容在哪里:

      vector<cls*> *vec = new vector<cls*>;
      

      向量在堆上,内容在它所在的任何地方(例如,如果你通过new分配它,它可能在堆上,或者如果你这样做,它可能在堆栈上:cls myCls; cls* myPointerToCls = &amp;cls;,然后@ 987654326@)

      【讨论】:

        【解决方案8】:

        好的,很多不错的答案,

        您需要迭代您的向量并单独删除每个元素

        我将展示一个小例子:

        class cls
        {
        
        public:
          cls(int x) :_a(x) {}
          ~cls() {cout<<"I'm Destroyed"<<endl ;}
         private:
         int _a;
        
        };
        
        int main()
        {
        vector<cls*> vec ;
        
        for(auto i=1;i<=10;i++)
            vec.push_back(new cls(i));
        
        for (auto it = vec.begin(); it != vec.end(); ++it) 
            delete *it;
        
        {
        vector<cls*> vec2 ;
        
        vec2.push_back(new cls(10));
        }
           //Here  vec2 out of scope
        }
        

        输出: 我被摧毁了

        【讨论】:

        • 我正在尝试通过索引访问矢量元素作为 delete *vec[0]。不可能吗?
        • @Saksham 引用我的示例delete vec2[0]; 将在该特定范围内工作。您可以看到打印的消息。
        猜你喜欢
        • 2019-10-01
        • 2014-05-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-07-03
        • 2016-05-07
        • 2011-07-19
        相关资源
        最近更新 更多