解除std :: vector对象的“正确”方法

时间:2010-06-16 15:08:26

标签: c++ stl vector memory-management

第一个解决方案是:

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 个答案:

答案 0 :(得分:36)

释放向量的最简单,最可靠的方法是在堆栈上声明它并且什么都不做。

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

C ++保证在方法执行时将调用v的析构函数。 std::vector的析构函数将确保释放它分配的任何内存。只要T的{​​{1}}类型具有适当的C ++释放语义,一切都会很好。

答案 1 :(得分:15)

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

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

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

答案 2 :(得分:13)

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();

答案 3 :(得分:3)

我同意Mike Seymour的观点 试试这个然后你会发现最后一个正常工作

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();

答案 4 :(得分:1)

除非确实需要,否则不要使用内存分配功能。如果你的类需要一个向量,总是直接和std :: vector成员一起使用。这里不需要进行内存分配。

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

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

答案 5 :(得分:1)

我的猜测是你有一个临时包含大量数据的向量。一旦矢量被清除,它仍将占用所有这些存储器。你想在完成它之后释放这个内存,但是你正在使用的函数/对象还没有完成。

满意度降序的解决方案:

  1. 重写代码,以便使用代码的向量位于其自己的块/函数/对象中,以便自然销毁它
  2. 使用交换技巧,这样您就不必担心确保在所有情况下都释放了向量。它的生命周期将与您所在的对象/功能联系在一起。
  3. new /删除矢量。这将比以前的方法释放更多的内存,但也更难确保没有内存泄露。
  4. 交换和删除之间唯一的技术差异是基本向量本身不会被破坏。这是一个很小的开销,不值得担心(只要你最终破坏了矢量)

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

答案 6 :(得分:0)

删除释放内存,然后内存为下一个对象释放,但向量已经消失。

第二个技巧释放了任何多余的内存,但保留了矢量,但是空的。

答案 7 :(得分:0)

虽然两者似乎都有效,但我认为没有理由不在指针上调用delete。向量应该有一个被调用的析构函数,它将处理其他所有内容。

答案 8 :(得分:0)

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

如果要保留向量但释放保存其内容的内存,则vec.swap(std::vector<int>());将执行此操作。除非vec包含您要保留的项目,并且您只想将分配的内存缩小到接近当前大小的值(),否则无需将临时构造复制到原始中。

答案 9 :(得分:0)

这不是有效的比较,因为这些示例涉及不同类型的对象:动态持续时间和本地持续时间。您可以调用析构函数或使用交换技巧(aka shrink_to_fit)。 正确的方式取决于您是否需要持久化矢量对象。

例如,你可能需要它坚持如果有引用或指针必须保持有效,在这种情况下,缩小是唯一的方法,无论它是如何分配的。

答案 10 :(得分:0)

我不确定为什么你的第二个例子使用临时构造函数而不是默认构造函数。这样可以节省.clear()代码行。

您可以为任何对象制作此通用对象,即使它不是容器。我在这里假设std :: swap专门用于调用vector :: swap。

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

std::vector<int> vec;  
//...  
ResetToDefault(vec);

答案 11 :(得分:0)

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

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

特别适用于以下代码:

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