![](/img/trans.png)
[英]Proper way to delete and free up memory of a vector (prevent different memory related errors) in c++
[英]C++ delete vector, objects, free memory
我对在 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();
您可以调用 clear,这将销毁所有对象,但不会释放内存。 循环遍历各个元素也无济于事(您甚至建议对对象采取什么行动?)您可以做的是:
vector<tempObject>().swap(tempVector);
这将创建一个没有分配内存的空向量,并将其与 tempVector 交换,从而有效地释放内存。
C++11 也有函数shrink_to_fit
,你可以在调用 clear() 之后调用它,理论上它会缩小容量以适应大小(现在是 0)。 然而,这是一个非绑定请求,您的实现可以随意忽略它。
这里有两件事:
例如:
{
vector<MyObject> v;
// do some stuff, push some objects onto v
v.clear(); // 1
// maybe do some more stuff
} // 2
在1
,您清除v
:这会破坏它存储的所有对象。 每个都调用它的析构函数,如果你写了一个,那么MyObject
拥有的任何东西现在都被释放了。 但是,vector v
有权保留原始存储,以备日后使用。
如果您决定在1
和2
之间将更多内容推入其中,则可以节省时间,因为它可以重用旧内存。
在2
,向量v
超出范围:从1
推入它的任何对象都将被销毁(就像您再次明确调用 clear 一样),但现在底层存储也被释放( v
不会出现在再使用它)。
如果我更改示例,使v
成为指向动态分配向量的指针,则您需要显式删除它,因为在2
处超出范围的指针不会为您执行此操作。 在这种情况下最好使用std::unique_ptr
类的东西,但如果你不这样做并且v
被泄露,它分配的存储也会被泄露。 如上所述,您需要确保v
被删除,并且调用clear
是不够的。
vector::clear()
不会释放 vector 分配的内存来存储对象; 它为它持有的对象调用析构函数。
例如,如果vector使用一个数组作为backing store,当前包含10个元素,那么调用clear()
会调用数组中每个对象的析构函数,但是backing数组不会被deallocated ,所以还是有sizeof(T) * 10
个字节分配给向量(至少)。 size()
将为 0,但size()
返回向量中的元素数,不一定是后备存储的大小。
至于您的第二个问题,您使用new
分配的任何内容都必须使用delete
解除分配。 出于这个原因,您通常不会维护指向向量的指针。 很少有(如果有的话)这样做的充分理由,并且当向量离开作用域时,您会阻止它被清理。 然而,不管它是如何分配的,调用clear()
仍然会以相同的方式运行。
如果我使用
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
移动语义允许通过简单地从空右值应用 赋值 (=) 运算符来提供一种直接的方法来释放内存:
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()”的方法一样有效(实际上,两者在概念上都在做同样的事情)。 然而,在可读性方面,作业版本在表达程序员意图方面做得更好,同时更简洁。
您可以通过这种方式释放 vector 使用的内存:
//Removes all elements in vector
v.clear()
//Frees the memory which is not used by the vector
v.shrink_to_fit();
如果您需要一遍又一遍地使用向量,并且您当前的代码在循环中或每次函数调用中重复声明它,则很可能会耗尽内存。 我建议你在外面声明它,在你的函数中将它们作为指针传递并使用:
my_arr.resize()
这样,您可以继续为向量使用相同的内存序列,而不是每次都请求新序列。 希望这有帮助。 注意:将其调整为不同的大小可能会添加随机值。 如果需要,传递一个整数(例如 0)来初始化它们。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.