之所以会有这样的疑问,是因为在写多线程程序的过程中经常用到vector作为序列消息的容器, 一个或多个向vector写入struct类型的元素,另外的一个或者多个线程取出元素加以处理,这也是大多数生产者消费者模型的最常用方式。在这个过程中有必要了解内存的分配和释放时机,以避免产生内存的泄漏。

typedef struct _TEST1
{
 TCHAR aryt[100];
} TEST1,*LPTEST1;

在这个过程中,有以下几个问题

1.struct变量在push_back()到vector的时候,vector怎样处理呢?

答案。如果vector是一个struct类型的容器,

typedef vector <TEST1> TV;

TV tv;

 TEST1 t1={0};
 LPTEST1 lpt1=&t1;
 memset(lpt1,'A',sizeof(TEST1)-1);
 tv.push_back(t1);
 memset(lpt1,'B',sizeof(TEST1)-1);
 lpt2=&(tv.at(0));
 TRACE("%d/n",tv.size());
 TRACE("%s/n",lpt2->aryt);

在上述代码中,t1变量被push_bak到vector中,是作为值来传递的,push_back()方法会申请一块新的内存,并把t1的值(也就是数组的值)复制到新的内存缓冲区中

lpt1和tv中的元素的指针是不同的,t1,*lpt1是BBBBBBBBBBBBBBBBBB,而tv中的元素值为AAAAAAAAAAAAAAAA

2.tv.clear()之后,lpt2和lpt1是怎样的?

上述代码中lpt1指向原来的内存地址,lpt2指向的是tv的元素地址

clear()之后lpt1不受任何影响,但是tv的元素和内存都被释放,包括原的内存快被回收,此时lpt2指向的内存中的内容是不可知的,并且是危险的。

3.tv.pop_back()之后,lpt2和lpt1的情况

pop_back是用来删除最后一个元素的,当然现在只有一个元素,删除之后,该vector就变为empty,按照惯例,被移除的元素应当被释放掉,此时访问lpt2应该也是无法取得正确的值

但是实际上,我们访问lpt2发现指向的内存块中的值依然没有变化,看起来好像没有被释放掉一样,但是按照正确和严谨的原则,lpt2不应当再被访问,因为这里的释放并非还给内存堆栈,而是被vector内部保留,只是无法通过方法访问到,

我们可以再push_back(t1),按照之前说的,应该是分配一个新的内存给新的元素,但我们发现,新的元素值所在的内存地址还是lpt2指向的那一块,只是值变成了BBBBBBBB....

这个时候,我们输出lpt1->aryt和lpt2->aryt都是BBBBB......,同一块内存地址在pop_back()和push_back之后,被重复使用了,这里很奇妙,pop_back删除和clear清除,是完全不同的,可以理解为,vector内部实现的时候为了效率而做的处理。那么pop_back的元素什么时候会被完全释放,这个还需要更进一步的深入了解

 

 

Logo

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

更多推荐