vector容器的迭代器实现以及迭代器失效问题

vector容器迭代器

vector容器迭代器类主要实现 operator*() operator!=() 以及 operator++() 的运算符

同时在全局实现获得首尾迭代器的 beginend 函数

迭代器失效问题

  • erase(it) 删除元素之后的所有元素的迭代器失效[it + 1, end)

  • insert(it, val) 插入元素之后位置的所有元素的迭代器失效 [it, end),若发生扩容,全部元素迭代器失效

  • 不同容器的迭代器不能进行比较

迭代器失效处理

在迭代器类中添加一个指向所迭代的容器对象的指针

链表组织已产生的迭代器对象,在发生pop_back, inserterase操作时对指定的指针范围对应的迭代器进行失效处理,即将迭代器的容器对象指针置为nullptr

// 容器迭代器失效用到的类
// 用链表组织创建过的迭代器
struct Iterator_Base
{
	Iterator_Base(iterator* c = nullptr, Iterator_Base* n = nullptr)
		: _cur(c), _next(n) {}
	iterator* _cur;
	Iterator_Base* _next;
};
Iterator_Base _head;

迭代器构造时头插

class iterator
{
public:
    friend class vector<T, Alloc>;
    iterator(vector<T, Alloc>* pvec = nullptr, T* ptr = nullptr)
        : _ptr(ptr)
        , _pVec(pvec)
    {
        // 头插法
        Iterator_Base* itb = new Iterator_Base(this, _pVec->_head._next);
        // _head不存实际的迭代器信息只是便于使用
        // 即带头节点的链表
        _pVec->_head._next = itb;
    }
private:
    T* _ptr;
    // 标识当前迭代器属于哪个容器对象
    vector<T, Alloc>* _pVec;
};

迭代器失效处理如下

// 检查容器迭代器对应指针是否在(first, last]范围内
// 若在,则使对应迭代器失效
void verify(T* first, T* last)
{
    Iterator_Base* pre = &this->_head;
    Iterator_Base* it = this->_head._next;
    while (it != nullptr)
    {
        // iterator* --- Iterator_Base::_cur
        // Iterator_Base* --- Iterator_Base::_next
        if (it->_cur->_ptr > first && it->_cur->_ptr <= last)
        {
            // 迭代器失效,把iterator持有的【所属容器】指针置为nullptr
            it->_cur->_pVec = nullptr; // 迭代器失效操作
            // 删除当前迭代器节点,继续判断后面的迭代器节点是否失效
            pre->_next = it->_next;
            delete it;
            it = pre->_next;
        }
        else
        {
            pre = it;
            it = it->_next;
        }
    }
}

带有迭代器以及失效处理的vector代码

#include <iostream>
using namespace std;

// 使用空间配置器将内存分配于对象构造分开
// template <class _Ty, class _Alloc = allocator<_Ty>>
// class vector
//容器的空间配置器allocator做4件事: 内存开辟/释放,对象构造/ 析构
template<typename T>
struct Allocator
{
	T* allocate(size_t size) // 内存开辟
	{
		return (T*)malloc(sizeof(T) * size);
	}
	void deallocate(void* p) // 释放内存
	{
		free(p);
	}
	void construct(T* p, const T& val) // 对象构造
	{
		new (p) T(val); // placement new
	}
	void destroy(T* p) // 对象析构
	{
		p->~T();
	}
};
template<typename T, typename Alloc = Allocator<T>>
class vector
{
public:
	vector(int size = 10)
	{
		// 需要把内存开辟和对象构造分开处理
		//_first = new T[size];
		// 只分配空间
		_first = _allocator.allocate(size);
		_last = _first;
		_end = _first + size;
	}

	~vector()
	{
		//delete[] _first;
		// 析构容器的【有效元素】,然后释放_first指针指向的堆内存
		for (T* p = _first; p != _last; ++p)
		{
			_allocator.destroy(_first);  //  析构有效元素
		}
		_allocator.deallocate(_first); // 释放堆上的数组内存
		_first = _last = _end = nullptr;
	}

	vector(const vector<T>& rhs)
	{
		int size = rhs.end - rhs._first;
		// _first = new T[size];
		_first = _allocator.allocate(size); // 先分配内存
		int len = rhs._last - rhs._first;
		for (int i = 0; i < len; ++i)
		{
			//_first[i] = rhs._first[i];
			_allocator.construct(_first + i, rhs._first[i]);
		}
		_last = _first + len;
		_end = _first + size;
	}

	vector<T>& operator=(const vector<T>& rhs)
	{
		// 防止自赋值
		if (this == &rhs)
		{
			return *this;
		}

		// 析构原来对象
		// delete[] _first;
		// 把_first指向的【有效元素】给析构掉
		for (T* p = _first; p != _last; ++p)
		{
			_allocator.destroy(p);
		}
		_allocator.deallocate(_first); // 内存释放


		int size = rhs.end - rhs._first;
		//_first = new T[size]; // 分配空间+创建对象,一步到位
		_first = _allocator.allocate(size); // #1 分配空间
		int len = rhs._last - rhs._first;
		for (int i = 0; i < len; ++i)
		{
			// _first[i] = rhs._first[i];
			// #2 构造对象
			_allocator.construct(_first + i, rhs._first[i]);
		}
		_last = _first + len;
		_end = _first + size;

	}
	void push_back(const T& val)
	{
		if (full())
		{
			expand();
		}
		//*_last++ = val; 
		_allocator.construct(_last, val);
		_last++;
	}
	void pop_back()
	{
		if (empty())
		{
			return;
		}
		//--_last; // 这样既没析构也没释放空间
		// 使指向(_last-1, _last]之间的迭代器失效
		verify(_last - 1, _last);
		--_last;
		_allocator.destroy(_last); // 要析构一下
	}

	T back() const // 返回容器末尾的元素值
	{
		return *(_last - 1);
	}

	bool full() const { return _last == _end; }
	bool empty() const { return _first == _last; }
	// 当前元素个数
	int size() const { return _last - _first; }
	T& operator[](int index)
	{
		if (index < 0 || index >= size())
		{
			throw "OutOfRangeException";
		}
		return _first[index];
	}

	// 迭代器本质就是对指针的封装
	class iterator
	{
	public:
		friend class vector<T, Alloc>;
		iterator(vector<T, Alloc>* pvec = nullptr, T* ptr = nullptr)
			: _ptr(ptr)
			, _pVec(pvec)
		{
			// 头插法
			Iterator_Base* itb = new Iterator_Base(this, _pVec->_head._next);
			// _head不存实际的迭代器信息只是便于使用
			// 即带头节点的链表
			_pVec->_head._next = itb;
		}
		bool operator!=(const iterator& it) const
		{
			// 检查是不是属于同一个容器
			if (_pVec == nullptr || _pVec != it._pVec)
			{
				throw "iterator incompatable!";
			}
			return _ptr != it._ptr;
		}
		void operator++()
		{
			// 检查迭代器有效性
			if (_pVec == nullptr)
			{
				throw "iterator invalid!";
			}
			_ptr++;
		}
		T& operator*()
		{
			if (_pVec == nullptr)
			{
				throw "iterator invalid!";
			}
			return *_ptr;
		}
		const T& operator*() const
		{
			if (_pVec == nullptr)
			{
				throw "iterator invalid!";
			}
			return *_ptr;
		}
	private:
		T* _ptr;
		// 标识当前迭代器属于哪个容器对象
		vector<T, Alloc>* _pVec;
	};

	//
	// 返回首元素迭代器
	iterator begin() { return iterator(this, _first); }
	// 返回尾后元素迭代器
	iterator end() { return iterator(this, _last); }


	// 检查容器迭代器对应指针是否在(first, last]范围内
	// 若在,则使对应迭代器失效
	void verify(T* first, T* last)
	{
		Iterator_Base* pre = &this->_head;
		Iterator_Base* it = this->_head._next;
		while (it != nullptr)
		{
			// iterator* --- Iterator_Base::_cur
			// Iterator_Base* --- Iterator_Base::_next
			if (it->_cur->_ptr > first && it->_cur->_ptr <= last)
			{
				// 迭代器失效,把iterator持有的容器指针置为nullptr
				it->_cur->_pVec = nullptr; // 迭代器失效操作
				// 删除当前迭代器节点,继续判断后面的迭代器节点是否失效
				pre->_next = it->_next;
				delete it;
				it = pre->_next;
			}
			else
			{
				pre = it;
				it = it->_next;
			}
		}
	}

	iterator insert(iterator it, const T& val)
	{
		// 在it位置插入元素,原来[it,end)的元素后移
		// 返回指向插入元素的迭代器
		// 1.不考虑扩容
		// 2. 不考虑 it._ptr的指针合法性
		verify(it._ptr - 1, _last); // (it._ptr - 1, _last]的迭代器都失效
		T* p = _last;
		// 
		while (p > it._ptr)
		{
			_allocator.construct(p, *(p - 1));
			_allocator.destroy(p - 1);
			p--;
		}
		_allocator.construct(p, val);
		_last++;
		return iterator(this, p);
	}
	iterator erase(iterator it)
	{
		// 删除it位置元素,原来[it + 1,end)的元素前移
		// 返回指向删除元素的下一元素的迭代器
		verify(it._ptr - 1, _last); // (it._ptr - 1, _last]的迭代器都失效
		T* p = it._ptr;
		while (p < _last - 1)
		{
			_allocator.destroy(p);
			_allocator.construct(p, *(p + 1));
			p++;
		}
		// 析构最后一个位置
		_allocator.destroy(p);
		_last--;
		return iterator(this, it._ptr);
	}
private:
	// 底层使用动态分配的数组来实现
	T* _first; // 指向数组起始位置
	T* _last; // 指向数组中有效元素的尾后位置
	T* _end; // 指向数组空间的尾后位置
	Alloc _allocator; // 定义容器的空间配置器对象

	// 容器迭代器失效用到的类
	// 用链表组织创建过的迭代器
	struct Iterator_Base
	{
		Iterator_Base(iterator* c = nullptr, Iterator_Base* n = nullptr)
			: _cur(c), _next(n) {}
		iterator* _cur;
		Iterator_Base* _next;
	};
	Iterator_Base _head;

	void expand() // 容器的二倍扩容
	{
		int size = _end - _first;
		// T* ptmp = new T[size * 2];
		T* ptmp = _allocator.allocate(size * 2);
		for (int i = 0; i < size; ++i)
		{
			// ptmp[i] = _first[i];
			_allocator.construct(ptmp + i, _first[i]);
		}
		//delete[] _first;
		for (T* p = _first; p != _last; ++p)
		{
			_allocator.destroy(p);
		}
		_allocator.deallocate(_first);

		_first = ptmp;
		_last = _first + size;
		_end = _first + 2 * size;
	}
};

int main(void)
{
	vector<int> vec(200);
	for (int i = 0; i < 20; ++i)
	{
		vec.push_back(rand() % 100 + 1);
	}

	auto it = vec.begin();
#if 1 // 在偶数前插入一个小1的数
	for (; it != vec.end(); ++it)
	{
		if (*it % 2 == 0)
		{
			// insert返回指向插入元素的迭代器
			it = vec.insert(it, *it - 1); // 更新迭代器
			++it;
		}
	}
#else	// 删除所有偶数
	while (it != vec.end())
	{
		if (*it % 2 == 0)
		{
			// 若写为vec.erase(it)则下一轮会用到失效迭代器,抛异常
			it = vec.erase(it); // 更新迭代器
		}
		else
		{
			++it;
		}
	}
#endif
	for (int v : vec)
	{
		cout << v << " ";
	}
	cout << endl;
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值