栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

stl容器使用中的注意事项(一)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

stl容器使用中的注意事项(一)

1、关于容器的两个概念

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

通常我们的做法会如下:

vector v1;
vector v2;

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

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

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

或者

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

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

vector v1;
vector 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的大小。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/289655.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号