vector::clear() 幕后与破坏

vector::clear() behind the scenes & destruction

本文关键字:clear vector      更新时间:2023-10-16

我研究了STL vector的实现。Vector容器实现为动态数组。clear()方法用于销毁vector中的所有元素,它将vector的大小设置为0,但容量保持不变。所以,如果我理解正确的话,所有的元素都被称为它们的析构函数,但是动态分配的内存仍然可用。为了仍然释放它,我们可以这样做:

Vec.swap( vector<T>() ); // Capacity = 0.

但是假设我们没有使用swap,只做了一个clear。内部实现(如果我错了请纠正我)大致等于以下内容(以非常简化的方式):

// A contained type:
struct C {
    int m;
    C() : m(123){}
};
C * arr = new C[10];  //  Suppose this is the internal array in the container

编辑:我知道上面的new操作符在实际实现中没有使用,STL使用allocator,我只是使用new作为测试用例来测试析构函数(这只是一个类比)。

// Calling clear() :
for(size_t i=0;i<SZ;i++)
    arr[i].~C();  //  Destroying ALL elements  
// some other actions . . .

但现在容量仍然是10,内存中还有一些数据可以访问:

// Accessing the vector at 0:
cout<<arr[0].m<<endl;  //  This prints 123

这是未定义的行为吗?似乎是这样,但我还是想确定一下。

也许如果我更深入地了解调用析构函数(关于堆栈内存)时会发生什么,我可以肯定地知道,这是否等于当程序超出函数的作用域时调用析构函数,或者在退出作用域之前调用析构函数被认为就像任何方法一样,对象的堆栈内存没有被释放?

免责声明:上面的代码是非常简化的,以象征clear()所做的一部分,这是我从我的研究中得出的结论,如果我错了,你可以纠正我。

std::vector<...>::clear()只是销毁对象并适当地设置其内部记录以表明没有对象,这是正确的。当访问被销毁的对象时,你会有未定义的行为:尽管数据中的位可能没有改变,但相关的对象也可能被销毁,并且它们的内存可能被回收用于其他目的。

在你的例子中,C只是存储一个int,并没有在析构函数中对它做任何事情,比特可能是不变的,但没有保证。特别是调试实现可能会浪费几个周期,故意将垃圾写入销毁对象的内存中。

只是一个旁注:std::vector<...>不会使用new C[n],而是通过分配器分配和释放原始内存。但是,这是一个细节。

如果我理解正确的话,你的主要问题是:

这是未定义的行为吗?

对于一个常规数组,是的,你有一个未定义的行为,原因在前面的答案中解释过。但是,如果试图用索引等于或大于大小(注意,不能超过容量)的std::vector的元素访问,则访问操作符将抛出std::out_of_range异常(尽管函数clear()确实调用了vector的每个元素的析构函数,并且不改变其容量,但它确实改变了vector包含多少元素的内部计数)。

您的程序使用的内存区域:堆栈和堆。你把arr向量地址放在堆内存中,但是m的值驻留在堆栈中。如果要删除堆内存,请使用delete [] arr,如果要删除未寻址内存,请使用

arr = NULL你的结构可以很容易地像这样修改

struct C {
int *m;
C(int value) {
    m=new int(value);
}
~C()
{
    delete m;
}

};