64

关于删除 C++ 中的内容,我完全感到困惑。如果我声明一个对象数组并且如果我使用clear()成员函数。我可以确定内存已被释放吗?

例如 :

tempObject obj1;
tempObject obj2;
vector<tempObject> tempVector;

tempVector.pushback(obj1);
tempVector.pushback(obj2);

我可以安全地调用 clear 来释放所有内存吗?还是我需要遍历才能一一删除?

tempVector.clear();

如果把这个场景改成对象的指针,答案会和上面一样吗?

vector<tempObject> *tempVector;
//push objects....
tempVector->clear();
4

7 回答 7

100

您可以调用 clear,这将销毁所有对象,但不会释放内存。循环遍历各个元素也无济于事(您甚至打算对对象采取什么行动?)您可以做的是:

vector<tempObject>().swap(tempVector);

这将创建一个没有分配内存的空向量并将其与 tempVector 交换,从而有效地释放内存。

C++11 还有一个函数shrink_to_fit,你可以在调用 clear() 之后调用它,理论上它会缩小容量以适应大小(现在为 0)。然而,这是一个不具约束力的请求,您的实现可以随意忽略它。

于 2012-05-05T18:59:17.323 回答
31

这里有两件事:

  1. 对象生命周期
  2. 储存期限

例如:

{
    vector<MyObject> v;
    // do some stuff, push some objects onto v
    v.clear(); // 1
    // maybe do some more stuff
} // 2

在处1,您清楚v:这会破坏它存储的所有对象。如果你写了一个,每个都会调用它的析构函数,并且MyObject现在释放它所拥有的任何东西。 但是,vectorv有权保留原始存储空间,以备日后使用。

1如果您决定在和之间插入更多内容2,这可以节省时间,因为它可以重用旧内存。

2处,向量v超出范围:您推入其中的任何对象都1将被销毁(就像您再次显式调用 clear 一样),但现在底层存储也被释放(v将不再重复使用它)。


如果我将示例更改v为指向动态分配向量的指针,则需要显式删除它,因为超出范围的指针2不会为您执行此操作。在这种情况下最好使用类似的东西std::unique_ptr,但如果你不这样做并且v被泄露,它分配的存储空间也会被泄露。如上所述,您需要确保v已删除,并且调用clear是不够的。

于 2012-05-05T19:08:36.457 回答
20

vector::clear()不释放向量分配的内存来存储对象;它为它持有的对象调用析构函数。

例如,如果向量使用数组作为后备存储并且当前包含 10 个元素,则调用clear()将调用数组中每个对象的析构函数,但后备数组不会被释放,因此仍然有sizeof(T) * 10字节分配给向量(至少)。 size()将为 0,但size()返回向量中元素的数量,不一定是后备存储的大小。

至于你的第二个问题,你分配给new你的任何东西都必须用delete. 由于这个原因,您通常不会维护指向向量的指针。很少(如果有的话)有充分的理由这样做,并且您可以防止向量在离开范围时被清理。clear()但是,无论它是如何分配的,调用仍然会以相同的方式进行。

于 2012-05-05T19:03:17.467 回答
7

如果我使用clear()成员函数。我可以确定内存已被释放吗?

不,clear()成员函数会破坏向量中包含的每个对象,但它会保持向量的容量不变。它影响向量的大小,但不影响容量。

如果要更改向量的容量,可以使用clear-and-minimize idiom,即创建一个(临时)空向量,然后交换两个向量。


您可以轻松了解每种方法如何影响容量。考虑以下函数模板,它clear()在传递的向量上调用成员函数:

template<typename T>
auto clear(std::vector<T>& vec) {
   vec.clear();
   return vec.capacity();
}

empty_swap()现在,考虑将传递的向量与空向量交换的函数模板:

template<typename T>
auto empty_swap(std::vector<T>& vec) {
   std::vector<T>().swap(vec);
   return vec.capacity();
}

两个函数模板都返回向量在返回时的容量,那么:

std::vector<double> v(1000), u(1000);
std::cout << clear(v) << '\n';
std::cout << empty_swap(u) << '\n';

输出:

1000
0
于 2019-08-10T14:20:23.503 回答
3

移动语义允许通过简单地从空右值应用赋值 (=) 运算符来释放内存:

std::vector<uint32_t> vec(100, 0);
std::cout << vec.capacity(); // 100

vec = vector<uint32_t>();    // Same as "vector<uint32_t>().swap(vec)";    
std::cout << vec.capacity(); // 0

它与其他答案中描述的基于“swap()”的方法一样有效(实际上,两者在概念上都在做同样的事情)。然而,在可读性方面,赋值版本在表达程序员意图方面做得更好,同时更简洁。

于 2020-07-31T17:27:40.703 回答
1

您可以通过这种方式释放向量使用的内存:

//Removes all elements in vector
v.clear()

//Frees the memory which is not used by the vector
v.shrink_to_fit();
于 2020-09-10T13:09:29.717 回答
0

如果您需要一遍又一遍地使用向量并且您当前的代码在循环中或在每个函数调用中重复声明它,那么您很可能会耗尽内存。我建议您在外部声明它,将它们作为指针传递给您的函数并使用:

my_arr.resize()

这样,您可以继续为您的向量使用相同的内存序列,而不是每次都请求新的序列。希望这有帮助。注意:将其调整为不同的大小可能会添加随机值。如果需要,传递一个整数,例如 0 来初始化它们。

于 2017-06-06T19:47:57.970 回答