1. 概述

使用STL中的vector容器,用来存储指针变量(即char*),那么当我们使用erase()函数去删除该容器中的指针变量元素时候,该指针变量申请的内存空间地址会不会被erase()函数在底层给释放掉?

这个问题是比较重要的。如果erase()函数不会去释放掉指针变量对应的内存空间,那么在我们没有手动去释放vector容器中的指针变量时候,会导致内存泄露,这是个十分严重的问题。

2. 验证

为了验证这个问题,我们写一个小demo来亲自测试看看结果现象。

我们定义两个指针变量pNamepAddr。然后分别申请相应大小(p1p2)的内存空间;若内存申请成功,则分别将p1p2中的字符串拷贝到pNamepAddr中。接着讲pNamepAddr这两个指针变量存储到vector容器(vPointers)中。然后打印vPointers容器中的所有元素值。

在删除vPointers容器所有元素之前,使用两个临时指针变量p3p4分别指向pNamepAddr所指向的内存空间。之后删除该vector容器(vPointers)中的所有元素(即pNamepAddr),

接着再次打印临时指针变量p3p4所指向的内存空间地址中的内容,发现依然有数据。内存空间并没有被erase()函数释放,因此,这表明erase()函数底层不会对用户的指针变量做任何操作,它仅仅负责删除vector容器中的元素罢了。

示例代码如下:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <assert.h>
#include <vector>
#include <list>
#include <iostream>
using namespace std;

int main()
{
    vector<char*> vPointers;
    char *p1 = "lixiaogang5", *p2 = "guizhousheng";

    //malloc不会对申请的内存空间清零.
    char *pName = (char*)calloc(1, strlen(p1) + 1);
    strncpy(pName, p1, strlen(p1));

    char *pAddr = (char*)malloc(strlen(p2) + 1);
    assert(pAddr);
    strncpy(pAddr, p2, strlen(p2));

    vPointers.push_back(pName);
    vPointers.push_back(pAddr);
    cout << "===============================================" << endl;
    cout<<"vPointers.size(): "<<vPointers.size()<<endl;
    for(auto &v : vPointers)
    {
        cout << v <<endl;
    }

    cout << "===============================================" << endl;
    //address
    printf("pName: %p, pAddr: %p\n", &(*pName), &(*pAddr));
    char *p3 = pName, *p4 = pAddr;
    printf("p3: %p, p4: %p\n", &(*p3), &(*p4));

    cout << "===============================================" << endl;
    auto it = vPointers.begin();
    for(; it != vPointers.end(); )
    {
        it = vPointers.erase(it);
    }

    cout << "vPointers.size(): "<<vPointers.size()<<endl;
    cout << "===============================================" << endl;
    cout << "p3: "<< p3 << endl;
    cout << "p4: "<< p4 << endl;
    cout << "===============================================" << endl;

    if(p3) free(p3), p3 = NULL;
    if(p4) free(p4), p4 = NULL;
    return 0;
}

打印结果如下图所示:

在这里插入图片描述

3. 源码分析erase()

stl_vector.h文件中,实现了vector容器的声明,其中也给出了erase()的函数原型。

erase()函数支持删除迭代器指定的一个元素、或是两个指定迭代器(__first__last)区间的所有元素。

#if __cplusplus >= 201103L
      erase(const_iterator __position)
      { return _M_erase(begin() + (__position - cbegin())); }
#else
      erase(iterator __position)
      { return _M_erase(__position); }
#endif
      iterator
#if __cplusplus >= 201103L
      erase(const_iterator __first, const_iterator __last)
      {
	const auto __beg = begin();
	const auto __cbeg = cbegin();
	return _M_erase(__beg + (__first - __cbeg), __beg + (__last - __cbeg));
      }
#else
      erase(iterator __first, iterator __last)
      { return _M_erase(__first, __last); }
#endif

从该源码中可看到erase()函数仅是删除指定迭代器对应的数据元素,而不会去调用类似free()之类的函数。

同样,clear()函数亦如此。

4. 总结

vector容器中的erase()函数仅删除迭代器所指定的数据元素,不会对用户本身的数据所过多的干涉。如果待存储vector容器中的元素是指针变量,需要用户自己去管理指针变量对应的内存空间地址。同理,clear()函数也一样。

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐