stl容器使用中的经验(十一)--erase-remove删除存储指针的容器元素

我们首先看个例子。

#include <iostream>
#include <vector> 
#include <list>
#include <algorithm>

using namespace std;

class Widget
{
public:
	Widget(int a) : m_a(a)
	{
		if(a % 2 == 0)
		{
			m_isMeasured = true;
		}
	}
	bool isMeasured()
	{
		return m_isMeasured;
	}
	
private:
	int m_a {0};
	bool m_isMeasured {false};
}; 

int main()
{
	typedef vector<Widget*> WidgetVec;
	typedef vector<Widget*>::iterator WidgetIter;
	
	WidgetVec v;
	
	for(int index = 0; index < 10; ++index)
	{
		v.push_back(new Widget(index));
	}
	
	for(WidgetIter i = v.begin(); i != v.end(); ++i)
	{
		cout << (*i)->isMeasured() << " "; // 1 0 1 0 1 0 1 0 1 0
	}
	
	return 0;
}

上面的例子中,我们首先定义一个类Widget,然后根据构造的时候的数值对成员变量m_isMeasured进行赋值。

接下来我们定义一个vector容器,用来存储创建的Widget指针。

当我们做了很多不知道为什么的操作之后,不知道是哪根筋搭错了,我就想把容器中对于没有被标记measured的对象删除。

而通常的方法我们就是选择自己写循环,对每个成员进行删除。但是不由得又想起来以前好像模糊中说过的,尽量使用算法而不是编写显示的循环

刚好,我们刚刚才在上一节中学习了erase-remove方法来删除容器的元素。也就很顺利的用来解决问题。

v.erase(remove_if(v.begin(), v.end(), not1(mem_fun(&Widget::isMeasured)));

不知道 not1mem_fun可以自行百度查询一下定义和用法。

但是前面我们好像有说过,删除容器中的指针并不能删除指针所指的对象,因此使用erase删除容器中的指针的时候,可能会造成内存泄漏。

但是在上面的这行代码中,你的担忧虽然正确但是已经迟了,它在调用erase之前就已经可能造成了内存的泄漏,为什么呢?

因为我们前面有看过remove系列的相关特点,remove在移动元素的时候,会将需要删除的元素移动到容器的末尾,而移动的过程中,会对前面需要删除的元素进行下一个不需要删除元素的赋值,赋值之后,只是改变了指针,原来的指针指向的内存就永远不会被释放了,也就造成了内存泄漏。

所以,我们需要在调用remove_if方法的时候,需要考虑删除需要被删除的指针指向的内存。

首先我们针对析构内存写一个判断方法,该方法实现的功能是,判断是否需要析构,如果需要,则析构指针指向的内存。并将指针置为 NULL。

void clenWidget(Widget*& p)
{
	if(!p->isMeasured())
	{
		delete p;
		p = NULL;
	}	
}

然后通过for_each区间函数遍历容器,对容器进行指针析构。

for_each(v.begin(), v.end(), clenWidget);

之后再针对已经析构了需要删除元素的容器进行元素的删除,现在的删除就能够正常的使用erase-remove的用法。

v.erase(remove(v.begin(), v.end(), static_cast<Widget*>(NULL)), v.end());

但是如果容器中存的不是普通指针,而是具有引用计数功能的智能指针,也就不用考虑remove造成的困难,而可以直接使用erase-remove习惯用法。

typedef shared_ptr<Widget> WidgetSptr;

vector<WidgetSptr> v;

v.push_back(WidgetSptr(new Widget));
...

v.erase(remove_if(v.begin(), v.end(), not1(mem_fun(&Widget::isMeasured))), v.end());

主要是因为编译器会将智能指针隐式的转换为其内置指针Widget*。容器中存放的是智能指针,但是成员函数isMeasured必须通过内置指针才能调用。

对存储指针的容器在使用remove系列函数时要注意内存泄漏,可以使用有引用计数的智能指针代替,或者在调用remove函数之前,对需要删除的指针进行内存析构并置为0.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值