C++ &引用;对",;取消分配std::vector对象的方法

C++ &引用;对",;取消分配std::vector对象的方法,c++,stl,vector,memory-management,C++,Stl,Vector,Memory Management,第一个解决方案是: std::vector<int> *vec = new std::vector<int>; assert(vec != NULL); // ... delete vec; std::vector*vec=新的std::vector; 断言(vec!=NULL); // ... 删除vec; 答案是: std::vector v; //... 向量清除(); 向量交换(std::vector(vec)); 第二个解决方案有点诡计——“正确”的方法是

第一个解决方案是:

std::vector<int> *vec = new std::vector<int>;
assert(vec != NULL);
// ...
delete vec;
std::vector*vec=新的std::vector;
断言(vec!=NULL);
// ...
删除vec;
答案是:

std::vector v;
//...
向量清除();
向量交换(std::vector(vec));
第二个解决方案有点诡计——“正确”的方法是什么

更新:
我知道析构函数一旦离开堆栈就会被调用,我对其他方法很好奇。

Delete释放内存,内存就可以用于下一个对象,但向量已经消失了


第二个技巧释放多余的内存,但保持向量不变,但为空。

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

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

C++保证在方法执行时调用
v
的析构函数。std::vector的析构函数将确保释放它分配的所有内存。只要<<代码> t/c>类型>代码>向量 >具有适当的C++去分配语义,都会很好。 尽管这两种方法似乎都有效,但我认为没有理由不在指针上调用delete。向量应该有一个称为析构函数的析构函数,它将处理所有其他内容

如果您只是让向量超出范围,它将在不做额外工作的情况下进行适当的清理。如果该向量是类的成员变量,并且您希望它在销毁其所有者之前释放其内容,那么只需调用vec.clear()


如果您想保留该向量,但取消分配保存其内容的内存,那么
vec.swap(std::vector())将完成此操作。除非vec包含您想要保留的项目,并且您只想将分配的内存缩小到接近当前大小的值(),否则无需将临时内存复制到原始内存中。

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

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

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

std::vector vi;
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();
/*把很多东西推到向量中*/ //在C++03中清理它 //不需要先清除() std::vector().swap(vi); //在C++0x中清理它 //不是一句台词,而是更地道的 vi.清除(); vi.收缩到合适的位置();
这不是一个有效的比较,因为示例涉及不同类型的对象:动态持续时间和本地持续时间。您可以调用析构函数或使用交换技巧(也称为shrink_to_fit)处理其中任何一个。正确的方法取决于是否需要向量对象持久化


例如,如果有指向它的引用或指针必须保持有效,则可能需要将其持久化,在这种情况下,收缩是唯一的方法,无论它是如何分配的。

我不确定为什么第二个示例使用复制构造函数作为临时构造函数而不是默认构造函数。这将为您节省
.clear()
行代码

您可以对任何对象进行泛型,即使它不是容器。这里我假设std::swap专门用于调用vector::swap

template<typename T>
void ResetToDefault(T & value)
{
    std::swap(T(), value);
}

std::vector<int> vec;  
//...  
ResetToDefault(vec);
模板
无效重置默认值(T和值)
{
std::swap(T(),value);
}
std::vec;
//...  
重置默认值(vec);

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

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

  • 重新编写代码,使使用代码的向量位于其自身的块/函数/对象中,从而使其自然销毁
  • 使用交换技巧,这样您就不必担心在任何情况下都要取消分配向量。它的生命周期将与您所在的对象/函数相关联
  • 新建/删除向量。这将比以前的方法释放多一点内存,但也更难确保没有内存泄漏
  • 交换和删除之间唯一的技术区别是基本向量本身没有被破坏。这是一个很小的开销,不值得担心(只要你最终销毁了向量)


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

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

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

    您的第二个变体将具有相同的效果,但它会在途中跳过更多的环。“复制和交换”技巧可以释放向量中的任何额外容量,如果它包含一些您想要保留的数据,那么它会很有用。如果没有数据,则无需复制或交换。

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

    std::auto_ptr<std::vector<int> > vec(new std::vector<int>);
    
    std::auto_ptr vec(新std::vector);
    
    特别适用于以下代码:

    std::auto_ptr<std::vector<int> > vec(vectorFactoryFunction());
    
    std::auto_ptr vec(vectorFactoryFunction());
    
    我同意迈克·西摩的观点 试试这个你就不会了
    std::auto_ptr<std::vector<int> > vec(vectorFactoryFunction());
    
    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();