在这篇文章之前的关于C++的文章都是介绍容器与容器内的一些简单的应用,并没有说明在什么样的场景下我们该选择什么样的容器,以及容器内保存什么的数据,是数据还是 pointer,都没有介绍,从这篇文章开始就要针对各个容器详细的看看他的使用案例
在介绍各个容器前需要了解 STL 容器共通的能力
1: 所有的容器STL 容器保存都是value ,而并非一个 reference ,容器进行插入动作时实际上进行copy或者move操作, 举个例子,vector vec 中每次push_back实际上是将 Persoon copy 到vector 容器内,并不是保存的Person的引用,想要实现这种情况有两种选择 wrapper 或者 使用智能指针
std::vector<std::shared_ptr<Person >> ttt;
在每次都进行拷贝构造的情况,如果你的 value 比较复杂,拷贝需要消耗的性能比较大,你就要考虑使用 move 操作了,
2:元素在容器内必须以特性顺序保存,并且可以使用迭代器访问到每一个元素,在使用迭代器进行多次遍历的过程中访问的是相同的路径,
3:一般而言各项操作都并非是绝对安全的,在进行数据操作前必须要保证操作函数的实参是具有意义的,违反条件可能会导致不明确行为,例子如下
vector<int> vec1={1,2,3};
vector<int> vec2;
std::copy(vec1.begin(),vec1.end(),vec2.begin());
由于使用的是 copy 并非insert ,并且vec2并没有实际分配内存的情况下,使用copy 就会将数据分配到野指针上面导致出现问题,
STL 共通操作
初始化 Initialization
每一个容器都提供了一个default 函数 和析构函数 ,以vector 为例
// 空构造函数
vector()
#if __cplusplus >= 201103L
noexcept(is_nothrow_default_constructible<_Alloc>::value)
#endif
: _Base() { }
//析构函数
~vector() _GLIBCXX_NOEXCEPT
{ std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
_M_get_Tp_allocator()); }
// 拷贝构造函数
vector(const vector& __x)
: _Base(__x.size(),
_Alloc_traits::_S_select_on_copy(__x._M_get_Tp_allocator()))
{ this->_M_impl._M_finish =
std::__uninitialized_copy_a(__x.begin(), __x.end(),
this->_M_impl._M_start,
_M_get_Tp_allocator());
}
再来看看常用用法都属于哪种类型,我们以 list 双向链表为例
//Initialization Type 构造,C++ 11 引入的
std::list<string> lis={"2","2","4"};
// 使用default 空构造函数,创建一个不含有任何元素的容器
std::list<Person> list;
// 使用拷贝构造函数,重新建立一个新的容器,将 list 中所有的元素 copy 到新的容器内
std::list<Person> l2(list);
// 使用拷贝构造函数,重新建立一个新的容器,将 list 中所有的元素 copy 到新的容器内
std::list<Person> l2=list;
//move
std::list<Person> l3(std::make_move_iterator(lis.begin()),std::make_move_iterator(lis.end()));
//从开始节点copy到结尾节点
std::list<Person> l4(lis.cbegin(),lis.cend());
//交换两个容器内的数据
ll1.swap(ll2);
// 获取数据量大小
lis.size();
//是否为空
lis.empty();
// 两个容器相等,
lis==list
从代码可以看出来两个容器相等的条件是数据类型相同,元素个数相同,切每个节点的元素相等
template<typename _Tp, typename _Alloc>
inline bool
operator==(const list<_Tp, _Alloc>& __x, const list<_Tp, _Alloc>& __y)
{
#if _GLIBCXX_USE_CXX11_ABI
if (__x.size() != __y.size())
return false;
#endif
typedef typename list<_Tp, _Alloc>::const_iterator const_iterator;
const_iterator __end1 = __x.end();
const_iterator __end2 = __y.end();
const_iterator __i1 = __x.begin();
const_iterator __i2 = __y.begin();
while (__i1 != __end1 && __i2 != __end2 && *__i1 == *__i2)
{
++__i1;
++__i2;
}
return __i1 == __end1 && __i2 == __end2;
}