Effective STL -- 容器

01.慎重选择容器类型

选择容器原则:需要考虑元素的排序情况,是否与标准相符,迭代器能力,元素布局,与C的兼容性,查找速度,引用计数,插入删除对事物语义的支持,某些操作是否会使迭代器无效,内存分配策略。

vector

需要使用随机迭代器

容器中布局需要与C兼容

deque

需要使用随机迭代器

当大多数插入在头部和尾部时

在尾部插入不会是迭代器,指针,引用变为无效

string

需要使用随机迭代器

介意使用引用计数计数,避免使用string,rope。string不可行

介意在容器上使用swap导致迭代器,指针,引用变成无效。string不可行

list

需要频繁的在中间插入删除

当大多数插入在头部和尾部时

对多个元素的插入删除需要事务语义

hash

查找速度是关键因素,选择优先级为hash->排序的vector->标准关联容器

关注元素的排序不可行

序列容器(vector string deque list slist rope)

需要在容器的任何位置插入新元素

关联容器

在容器中任意位置插入元素不可行

基于节点的容器(list,slist,关联容器,hash)

在单个节点插入删除时需要回滚能力

使迭代器,指针,引用变为无效的次数最少

元素插入删除时,避免移动容器中原来的元素

连续内存容器(vector,deque,string)

02.不要试图编写独立于容器类型的代码

原因:

  • 不同容器的函数集不同
  • 不同容器的同名函数返回值不同
  • 不同容器使迭代器失效的规则不同
  • 所编写代码只能使用这些容器的交集

03.确保容器中的对象拷贝正确而高效

注意点:

  • 存放基类对象的容器,向其中插入派生类对象,会导致剥离。
  • 使拷贝动作高效,正确,并防止剥离问题发生的一个简单办法使在容器中包含指针而不是对象。

04.调用empty而不是检查size()是否为0

原因:

  • 使用empty性能优于判断size()是否为0
  • empty是常数时间,有些list实现可能是线性时间
  • list的size()和splice()只有一个可实现为常数时间。

05.区间成员函数优先于与之对应的单元素成员函数

遗留问题:

vector::assign的实现方式

结论:

所有通过利用插入迭代器来限定目标区间的copy调用,都可以替换为对区间成员函数的调用。

使用区间函数避免频繁调用分配子,提升性能。

区间成员函数有:构造函数,区间插入,区间删除,区间赋值。

06.当心C++编译器最烦人的分析机制

以标准输入装置完成初始化操作

以下为错误写法:

std::deque<int> c(std::istream_iterator<int> (std::cin), std::istream_iterator<int>());

以上c被解析为函数声明。返回值为std::deque<int>,第一个参数型别为std::istream_iterator,参数名为cin。第二个参数无名称,型别是一个函数,不接受任何参数,返回值为std::istream_iterator<int>。

正确写法如下:

std::deque<int> c((std::istream_iterator<int> (std::cin)),(std::istream_iterator<int>()));

07.如果容器中包含了通过new操作符创建的指针,切记在容器对象析构前将指针delete掉

void doSomething()

{

    vector<Widget*> vwp;

    //

    do something

    //

    for (vector<Widget*>::iterator i = vwp.begin(); i!= vwp.end(); ++i)

        delete *i

}

以上代码问题:在do something部分发生异常,则会造成资源泄露,vector中的动态申请的Widget不会被释放。

解决方法:使用boost库中的share_ptr智能指针。发生异常时,栈中对象的析构函数均会被调用。

删除指针的仿函数模板

class DeleteObject {

    template<typename T>

        void operator()(const T* ptr) const {

        delete ptr;

    }

}

08.切勿创建包含auto_ptr的容器对象

09.慎重选择删除元素的方法

删除指定值

vector,string,deque:c.erase(remove(c.begin(), c.end(), value));

list:c.remove(value);

set,multiset,map,multimap:c.erase(value);基于等价(<)进行删除

删除判别式为true的值

vector,string,deque:c.erase(remove_if(c.begin(), c.end(), judge));

for (SeqContainer<int>::iterator i = c.begin; i != c.end();) {

    if (judge(*i)) {

        // 处理*i

        i = c.erase(*i);

    }

    else ++i;

}

list:c.remove_if(judge);

set,multiset,map,multimap:

remove_copy_if;c.swap

AssocContainer<int> c;

for (AssocContainer<int>::iterator i = c.begin(); i != c.end();) {

    if (judge(*i)) c.erase(i++)

    else ++i

}
时间: 2024-10-14 15:26:14

Effective STL -- 容器的相关文章

effective stl(容器部分总结)

还是很喜欢effective部分的书,看了好几遍,这里把stl中和容器相关的一些基本的注意的点进行介绍总结,之后对迭代器等进行总结 1 对序列容器中需要逐个删除的时候,不能像关联容器那样事先对迭代器进行++操作,因为删除一个迭代器,会使他自己无效,后面的迭代器也无效,所以应该保存删除erase返回的下一个指针的值.而关联容器中并不会导致后面的迭代器无效的情况 2 在stl中如果对容器内对象使用了new操作,一定要释放掉,因为析构函数没办法完成,这里最好使用智能指针,但是不要使用auto_ptr的

Effective STL 第7条:如果容器中包含了通过new操作创建的指针,切记在容器对象析构前将指针delete掉

STL中的容器相当"聪明",它们提供了迭代器,以便进行向后和向前的遍历(通过begin.end.rbegin等):它们告诉你所包含的元素类型(通过它们的value_type类型定义):在插入和删除的过程中,它们自己进行必要的内存管理:它们报告自己有多少对象,最多能容纳多少对象(分别通过size和max_size):当然,当它们自身被析构时,它们自动析构所包含的每个对象. 有了这么"聪明"的容器,许多程序员不再考虑自己做善后清理工作.更糟糕的是,他们认为,容器会考虑为

Effective STL 条款1:仔细选择你的容器

条款1:仔细选择你的容器 了解各种容器的实现方法,知道各种容器的内存管理方式.各种操作所对应的底层操作,然后根据需要选择恰当的容器. 对于容器的分类: 标准STL序列容器:vector,string,deque和list 标准STL关联容器:set,multiset,map和multimap 非标准序列容器:slist(单向链表)和rope(重型字符串--不懂) 非标准关联容器:hash_set,hash_multiset,hush_map和hash_multimap vector == str

Effective STL 第1条:慎重选择容器类型

C++提供了几种不同的容器供我们选择,这里简单回顾一下: 1.标准STL序列容器:vector.string.deque和list. 2.标准STL关联容器:set.multiset.map.和multimap. 3.非标准序列容器slist和rope.slist是一个单向链表,rope本质上是一"重型"string. 4.非标准关联容器hash_set.hash_multiset.hash_map和hash_multimap. 5.vector<char>作为string

C++:标准string或者STL容器不含virtual析构函数,所以不应该被继承——摘自Effective C++中文版第三版P42

即使class完全不带virtual函数,被“non-virtual析构函数问题”给咬伤还是有可能的.举个例子,标准string不含任何virtual函数,但有时候程序员会错误的把它当做base class: 1 // 馊主意,std::string有个non-virtual析构函数 2 class SpecialString: public std::string{ 3 ... 4 }; 乍看似乎无害,但如果你在程序任意某处无意间将一个pointer to SpecialString转换成一个

Effective STL 中文版(大全)

Effective STL 中文版(大全) 作者:winter 候捷说,对于STL,程序员有三个境界,开始是使用STL,然后是理解STL,最后是补充STL.Effective STL是一本非常好的书,帮助你更好的理解STL,其作者就是<Effective C++>一书的作者.如果你已经初步了解了STL的容器.迭代器.算法和函数,而又想更好的了解STL,那么<Effective STL>是你的最佳选择. 还有一部分没有找到链接,如果再找不到我会自己试着翻译一下:) 前言 容器 条款1

迅速读懂:Effective STL (五)

这是<Effective STL>笔记最后一期,不能涵盖全部内容,书后仍然有些附加内容,不在附加,有兴趣可以找原书来读读,一则是区域设置后的忽略大小写比较,另一则是MSVC4-5编译器下STL注意事项 条款41:了解使用ptr_fun.mem_fun和mem_fun_ref的原因 函数和函数对象总使用用于非成员函数的语法形式调用.mem_fun带有一个到成员函数的指针,pmf,并返回一个mem_fun_t类型的对象.这是一个仿函数类,容纳成员函数指针并提供一个operator(),它调用指向在

Effective STL读书摘要(一)

一直在用STL,认为对STL也有一些理解,比如比较函数怎么写,什么情况下用什么容器效率高,但是当你读过Effective STL之后才知道这远远不够,之前的代码还有很多可以优化的空间,下面我会罗列一些映像比较深的点,比较偏向代码因为这样可以方便以后的调用.这里是到Item29,余下的留下次看. 1) 检查容器是否为空 if(c.empty()){}   better than if(c.size()==0){} 2)如果能用批量操作函数就不要用循环来做 批量操作可以提高效率,要有能用批处理尽量批

STL容器简介

C++标准定义了一系列的容器的共通要求,适用于所有的STL容器,然而由于C++11带来了容器的多样化,因此可能出现若干例外. ?初始化: 每个容器都提供了一个default构造函数,一个copy函数和一个析构函数 ? ? ?