繁体   English   中英

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)。 然而,这是一个非绑定请求,您的实现可以随意忽略它。

这里有两件事:

  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拥有的任何东西现在都被释放了。 但是,vector v有权保留原始存储,以备日后使用。

如果您决定在12之间将更多内容推入其中,则可以节省时间,因为它可以重用旧内存。

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM