deque 居然已经实现了 insert 接口
最近有个开发需求,根据server传递来的广告位来展示某条广告。
但最终存储广告的数据结构是deque,里面存储的东西还是对象(stl 基于拷贝语义)。
想了半天,在开头和结尾插入比较方便,在中间插入就有些困难了——因为是双端队列,思维惯性啊!
另外一个问题deque中存储的是对象,这个涉及到覆盖和新的拷贝问题,如果对象很大(这就是现实),那会影响性能。
网上
但是产品需要摆在那边,没办法需要实现啊,只能在可能的情况下,尽量减少拷贝。
于是想到如果插入位置在deque的前半部分,就对deque的前半部分进行操作(pop_front等),如果在deque的后半部分,
就在deque的后半部分(push_back())进行操作。
实现的过程中,有些接口忘了,去cppreference.com 上去查deque的接口,发现deque有insert接口——当时就崩溃了,有木有!!!
http://en.cppreference.com/w/cpp/container/deque/insert
iterator insert( iterator pos, const T& value );
于是直接调用接口就好了,STL的实现比直接造的轮子好!!!!
但这个不是结束,为什么deque会提供insert接口,它怎么实现的,是否会避免一些数据的拷贝?带着这个问题,我查看了下4.1.2的源码。
template <typename _Tp, typename _Alloc> typename deque<_Tp, _Alloc>::iterator deque<_Tp, _Alloc>:: insert(iterator position, const value_type& __x) { if (position._M_cur == this->_M_impl._M_start._M_cur) { push_front(__x); return this->_M_impl._M_start; } else if (position._M_cur == this->_M_impl._M_finish._M_cur) { push_back(__x); iterator __tmp = this->_M_impl._M_finish; --__tmp; return __tmp; } else return _M_insert_aux(position, __x); }
可以看到这个函数,先判断了pos的位置,如果在前面插入,则调用push_front,如果在末尾插入,则调用push_back。
我们关注的在中间插入,走向了_M_insert_aux函数。
template <typename _Tp, typename _Alloc> typename deque<_Tp, _Alloc>::iterator deque<_Tp, _Alloc>:: _M_insert_aux(iterator __pos, const value_type& __x) { difference_type __index = __pos - this->_M_impl._M_start; value_type __x_copy = __x; // XXX copy if (static_cast<size_type>(__index) < size() / 2) { push_front(front()); iterator __front1 = this->_M_impl._M_start; ++__front1; iterator __front2 = __front1; ++__front2; __pos = this->_M_impl._M_start + __index; iterator __pos1 = __pos; ++__pos1; std::copy(__front2, __pos1, __front1); } 。。。。。
这个的实现,与我们当时的设想很类似,即看插入的位置与中间元素的关系,如果在前面,则push_front,否则push_back
总结1. STL的人很有爱(某人说的),这个接口都提供了,而且实现效率还可以。
2. STL的接口文档需要经常看看,避免造轮子。