stl容器使用中的经验(一)--stl容器的选择和基本概念

1、关于容器的两个概念

1、连续内存容器(基于数组的容器)

将其元素放在一块或多块(动态分配)的内存中,每块内存中有多个元素。当有新元素插入或者已有元素删除时,统一内存块中的其他元素要向前或向后移动,以便为新元素让出空间,或者填补删除元素的空间。这种移动会影响效率和异常安全,标准的连续容器:vector list deque。

2、关联容器(基于节点的容器)

基于节点的容器在每一个(动态分配)内存块上只存储一个元素。元素的插入和删除只会影响指向节点的指针,并不会影响节点本身的内容。因此当插入或者删除时,元素的值不需要移动。

2、容器的选择和容器切换之间的问题

日常经验中,容器的选择是个艰难的过程,虽然我们按照自己的需求确定好了容器,但无可避免的,我们可能会意识到自己的选择并不是最佳答案的时候,改变容器的类型就会是一个痛苦的过程(比如我们从vector容器切换为map容器)。

我们不仅要修改编译器诊断出的问题,还要进行一次比较详细的检查,因为新容器的性能特点,它使迭代器、指针、应用可能无效的规则。

我们考虑用封装来解决这个问题。

class Widget{...}
vector<Widget> vw;
Widget bestWidget;

vector<Widget>::iterator iter = find(vw.begin(), vw.end(), bestWidget);

上面的例子定义了一个普通的vector容器,也是我们在日常中最常用的一种方式,但是如果我们按照上面的案例编写写代码,并不可避免的进行容器的更换,那么我们就会解决上面提到的所有问题。

class Widget{...}
typedef vector<Widget> WidgetContainer;
typedef WidgetContainer::iterator WCIterator;
WidgetContainer cw;
Widget bestWidget;

WCIterator iter = find(cw.begin(), cw.end(), bestWidget);

上面提到的解决办法是,我们将容器进行封装,这样,在我们能切换容器的时候,或许只是会修改容器类型。

3、区间成员函数优先于针对单元素的成员函数

为什么说区间成员函数优先于与之对应的单元素的成员函数?好处不仅仅是只有一点。

如果需要对矢量进行赋初值或者进行拷贝的时候,区间成员函数,显示出了较单元素来说非常强大的代码能力。

通常我们的做法会如下:

vector<int> v1;
vector<int> v2;

v1.clear();
for(vector<int>::iterator iter = v2.bengin(); iter != v2.end(); ++iter)
{
    v1.push_back(*iter);
}

通常的我们的做法是写一个循环,对每一个元素进行插入,而这样就是我们不可避免的要使用循环。就算我们使用一个其他的方法,比如:

vector<int> v1;
vector<int> v2{1, 3, 4, 6};
copy(v2.bengin(), v2.end(), back_inserter(v1));

或者

v1.insert(v1.end(), v2.bengin(), v2.end());

如上,上述的算法例子,虽然我们表面看不到有循环的出现,但是函数的背后肯定是有的。如下,我们直接使用assign成员函数,直接简明。

vector<int> v1;
vector<int> v2;

v1.assign(v2.bengin(), v2.end());

1、能够减少代码
2、能够是代码意图更明显

4、stl容器线程安全性

  • 多线程读取时安全的。多个线程和同时读取同一个容器,但在读的过程中不能有写操作。
  • 多个线程对不同的容器做写操作时安全的。

因此,在多线程中,我们需要考虑:

  • 对容器成员函数的每次调用,都锁住容器直到调用结束;
  • 对容器返回的每个迭代器的生命周期中,都锁住容器;
  • 对于作用于容器的每个算法,都锁住该容器,直到算法调用结束。

5、对容器判空时使用empty()而非size() == 0

对于一个容器,其实if( size() == 0 ){...}if( empty() ){...} 本质上等价的。

那么为什么会推荐使用empty() 呢?主要是因为:该方法对任何一个容器来说,时间消耗都是常数级的,而 size() 对有些list的实现来说,耗时是线性的。

因为 list 是可以 splice 的,也就是list的拼接时并不知道自己本身元素的大小,如果想让list也能够有 size()常数级的操作,那就要保证list的每个成员函数都需要更新其size的大小。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值