代码之家  ›  专栏  ›  技术社区  ›  Jacob

取消分配std::vector对象的“正确”方法

  •  32
  • Jacob  · 技术社区  · 14 年前

    第一个解决方案是:

    std::vector<int> *vec = new std::vector<int>;
    assert(vec != NULL);
    // ...
    delete vec;
    

    alternative 是:

    std::vector<int> v;
    //...
    vec.clear();
    vec.swap(std::vector<int>(vec));
    

    第二个解决方案是一个小把戏——什么是“正确”的方法?

    更新:

    我知道一旦析构函数从堆栈中去掉,它就会被调用,我对其他方法很好奇。

    12 回复  |  直到 9 年前
        1
  •  35
  •   JaredPar    14 年前

    解除分配向量的最简单和最可靠的方法是在堆栈上声明它,而不做任何事情。

    void Foo() {
      std::vector<int> v;
      ...
    }
    

    C++保证了析构函数。 v 将在方法执行时调用。的析构函数 std::vector 将确保释放它分配的任何内存。只要 T 类型 vector<T> 适当的C++分配语义都会很好。

        2
  •  15
  •   Mike Seymour    14 年前

    在不破坏向量对象本身的情况下,释放向量中所有存储的最简单方法是

    vec = std::vector<int>();
    

    你的第二个变种也会有同样的效果,但它会在途中跳过更多的圈。“复制和交换”技巧会释放向量中的任何额外容量,如果它包含一些您想要保留的数据,则会很有用。如果没有数据,那么就不需要复制或交换。

        3
  •  12
  •   deft_code    14 年前
    std::vector<int> vi;
    /*push lots of stuff into the vector*/
    
    // clean it up in C++03
    // no need to clear() first
    std::vector<int>().swap(vi);
    
    // clean it up in C++0x
    // not a one liner, but much more idiomatic
    vi.clear();
    vi.shrink_to_fit();
    
        4
  •  3
  •   Sam    9 年前

    我同意迈克·西摩的观点 试试这个,你会发现最后一个很好用

    const int big_size = 10000;
    vector<double> v( big_size );
    cout << "Before clearing, the capacity of the vector is "
      << v.capacity() << " and its size is " << v.size();
    v.clear();
    cout << "\nAfter clearing, the capacity of the vector is "
      << v.capacity() << " and its size is " << v.size();
    vector<double>().swap( v );
    
    cout << "\nAfter swapping, the capacity of the vector is "
      << v.capacity() << " and its size is " << v.size();
    
    vector<double> v1( big_size );
    v1 = vector<double>();
    cout << "\n After vector<double>();, the capacity of the vector is "
      << v1.capacity() << " and its size is " << v1.size();
    
        5
  •  1
  •   Patrick    14 年前

    除非确实需要,否则不要使用内存分配函数。如果您的类需要一个向量,那么总是直接添加std::vector成员。这里不需要做内存分配。

    在需要动态向量的情况下,像在第一个示例中那样分配和删除它是100%正确的。

    在第二个示例中,对std::swap的调用是严格不需要的,因为clear方法将清除向量,使其为空。一个可能的问题是,无法保证向量将实际释放内存,并将其返回到操作系统(或运行时)。矢量可能会保留分配的内存,以防清除后立即填充矢量。调用std::swap可能是“强制”向量释放其内部数据的一个技巧,但不能保证这将实际发生。

        6
  •  1
  •   Winston Ewert    14 年前

    我猜这里有一个向量,它暂时包含了大量的数据。一旦向量被清除,它仍然会占用所有的内存。您希望在处理完内存之后释放它,但是您正在处理的函数/对象尚未完成。

    按期望值降序排列的解决方案:

    1. 重新编写代码,使使用代码的向量位于它自己的块/函数/对象中,从而自然地将其销毁。
    2. 使用交换技巧,这样就不必担心在任何情况下都要释放向量。它的生命周期将与您所在的对象/函数相关联。
    3. 新建/删除矢量。这将比以前的方法释放更多的内存,但也很难确保没有内存泄漏。

    交换和删除之间唯一的技术区别是基向量本身没有被破坏。这是一个很小的开销,不值得担心(只要你最终摧毁了向量)

    更大的考虑是,这样更容易编写正确的代码,我相信交换比删除更容易,但比将向量移动到其他地方更糟糕。

        7
  •  0
  •   Martin Beckett    14 年前

    删除取消分配内存,然后内存可供下一个对象使用,但向量已消失。

    第二个技巧释放任何多余的内存,但保持向量完整,但为空。

        8
  •  0
  •   Ben313    14 年前

    虽然这两种方法看起来都有效,但我没有理由不直接调用指针上的delete。向量应该有一个调用的析构函数来处理其他一切。

        9
  •  0
  •   Alan    14 年前

    如果您只是让向量超出范围,它将适当地清理自己,而不需要额外的工作。如果向量是类的成员变量,并且您希望它在其所有者被破坏之前释放其内容,那么只需调用vec.clear()。

    如果您想保留向量,但取消分配保存其内容的内存,那么 vec.swap(std::vector<int>()); 会的。不需要将构造临时对象复制到原始对象中,除非vec包含要保留的项,并且只希望将分配的内存缩小到接近当前大小的值()。

        10
  •  0
  •   Cubbi    14 年前

    这是无效的比较,因为示例处理的对象类型不同:动态持续时间和本地持续时间。你可以调用析构函数或者使用交换技巧(也就是收缩匹配)。这个 正确的 方式取决于是否需要向量对象来持久化。

    例如,您可能需要它来保持 如果有引用或指向它的指针 这必须保持有效,在这种情况下,收缩是唯一的方法,不管它是如何分配的。

        11
  •  0
  •   fredoverflow    14 年前

    我不知道为什么第二个示例将复制构造函数用于临时构造函数而不是默认构造函数。那会救你的 .clear() 代码行。

    您可以将此设置为任何对象的通用,即使它不是容器。我假设std::swap专门用于调用vector::swap。

    template<typename T>
    void ResetToDefault(T & value)
    {
        std::swap(T(), value);
    }
    
    std::vector<int> vec;  
    //...  
    ResetToDefault(vec);
    
        12
  •  0
  •   Graphics Noob    14 年前

    如果向量确实需要在堆中,请不要忘记:

    std::auto_ptr<std::vector<int> > vec(new std::vector<int>);
    

    尤其适用于以下代码:

    std::auto_ptr<std::vector<int> > vec(vectorFactoryFunction());