Effective STL笔记

  1. 条款4:用empty来代替检查size()是否为0

    对于所有的标准容器,empty是一个常数时间的操作,但对于一些list实现,size花费线性时间。

  2. 条款13:尽量使用vector和string来代替动态分配的数组

    VS2015编译器中sizeof(string)为28,具体内容在堆中。

    string对象的大小可能从1到至少7倍char*指针的大小,与具体的实现有关。

  3. 条款16: 如何将vector和string的数据传给遗留的API

    遗留的API: void dosomething(int *a)

    对于vector<int> v; 我们可以传入:&v[0]当然要判断v是否为NULLv,否则v [0]不存在

    但是函数内部不能改变v的内容。v是个对象,内部有相关信息。改变之后不能反映到内部信息中。

    你可能会碰到一些半吊子的人物,他们会告诉你说可以用v.begin()代替&v[0],

    对于vector,其迭代器实际上是指针。那经常是正确的,

    但正如条款50所说,并不总是如此,你不该依赖于此。应该是&*v.begin()好些。

    如果你正在和告诉你使用v.begin()代替&v[0]的人打交道的话,你该重新靠虑一下你的社交圈了。

    类似从vector上获取指向内部数据的指针的方法,对string不是可靠的,因为(1)string中的数据并没有保证被

    存储在独立的一块连续内存中,(2)string的内部表示形式并没承诺以一个null字符结束。这解释了string的成

    员函数c_str存在的原因,它返回一个按C风格设计的指针,指向string的值。因此我们可以这样传递一个string

    对象s给这个函数。

    doSomething(s.c_str());//即使是字符串的长度为0,它都能工作。但是形参类型是const的。不能改变。

  4. 条款17:使用“交换技巧”来修整过剩容量

  5. 条款18:避免使用vector<bool>

    第一,它不是一个STL容器。第二,它并不容纳bool。

  6. 条款20:为指针的关联容器指定比较类型

    set<string*> ssp; // ssp = “set of string ptrs”
    ssp.insert(new string("Anteater"));
    ssp.insert(new string("Wombat"));
    ssp.insert(new string("Lemur"));
    ssp.insert(new string("Penguin"));

    然后你写了下列代码打印set的内容,希望字符串按字母顺序出现

    set<string*, less<string*> > ssp;

    你不能使用默认比较仿函数类less<string*>。你必须改为写你自己的比较仿函数类,它的对象带有string*指针并按照指向的字符串值来进行排序。

    struct StringPtrLess{
    bool operator()(const string *ps1, const string *ps2) const
    {
    return *ps1 < *ps2;
    }
    };

  7. 条款22:避免原地修改set和multiset的键

    修改一个值只能先删除再插入

  8. 条款23:靠虑用有序vector代替关联容器

    当需要一个提供快速查找的数据结构时,很多STL程序员立刻会想到标准关联容器:set、multiset、map和

    multimap。直到现在这很好,但不是永远都好。对于只是查找没有过多删除插入的情况下vector有优势。

  9. 条款24:当关乎效率时应该在map::operator[]和map-insert之间仔细选择

    如果你要更新已存在的map元素,operator[]更好,但如果你要增加一个新元素,insert则有优势。

    map::operator[]有三次函数调用:一个建立临时的默认构造Widget对象,一个销毁那个临时的对象和一个对Widget的赋值操作。那些函数调用越昂贵,你通过使用map-insert代替map::operator[]就能节省越多。

  10. 条款26:尽量用iterator代替const_iterator,reverse_iterator和const_reverse_iterator

  11. 条款27:用distance和advance把const_iterator转化成iterator

    distance返回两个指向同一个容器的iterator之间的距离;advance则用于将一个iterator移动指定的距离。如果i和ci指向同一个容器,那么表达式advance(i, distance(i, ci))会将i移动到与ci相同的位置上。

  12. 条款31:了解你的排序选择

    内部实现原理:partial_sort。。。nth_elemen。。。stable_sort(稳定的)。。。

    算法sort、stable_sort、partial_sort和nth_element需要随机访问迭代器,所以它们可能只能用于vector、string、

    deque和数组。对标准关联容器排序元素没有意义,因为这样的容器使用它们的比较函数来在任何时候保持

    有序。唯一我们可能会但不能使用sort、stable_sort、partial_sort或nth_element的容器是list,list通过提供sort成

    员函数做了一些补偿。(有趣的是,list::sort提供了稳定排序。)所以,如果你想要排序一个list,你可以,但

    如果你想要对list中的对象进行partial_sort或nth_element,你必须间接完成。一个间接的方法是把元素拷贝到

    一个支持随机访问迭代器的容器中,然后对它应用需要的算法。

  13. 条款39:用纯函数做判断式

    纯函数是返回值只依赖于参数的函数。如果f是一个纯函数,x和y是对象,f(x, y)的返回值仅当x或y的

    值改变的时候才会改变。

    一个设计良好的判断式类也保证它的operator()函数独立于任何那类对象。在判断式类中把operator()声明为const对于正确的行为来说是必要的,但不够充分。一个行为良好的operator()当然是const,但不只如此。它也得是一个纯函数。

    bool anotherBadPredicate(const Widget&, const Widget&)

    {

    static int timesCalled = 0; // 不!不!不!不!不!不!不!

    return ++timesCalled == 3; // 判断式应该是纯函数,独立于任何对象。

    } // 纯函数没有状态

  14. 条款34:注意哪个算法需要有序区间

    binary_search。。merge。。

    merge(fst1,last1,fst2,last2, destIterator)//最后为输出迭代器

  15. 把仿函数类设计为用于值传递

    如果函数对象是引用传递,有些STL算法的实现甚至不能编译。所以,第一,你的函数对象应该很小。否则它们的拷贝会很昂贵。第二,你的函数对象必须单态(也就是,非多态)——它们不能用虚函数。那是因为派生类对象以值传递代入基类类型的参数会造成切割问题:在拷贝时,它们的派生部分被删除。

  16. 条款43:尽量用算法调用代替手写循环

    for (  ;i != lw.end();++i) {  } //lw.end()多次求职,效率低,特别是链表时。

    你几乎不可能打败内置算法。

  17. 条款44:尽量用成员函数代替同名的算法

    首先,成员函数更快。其次,比起算法来,它们与容器结合得更好(尤其是关联容器)。

    那是因为同名的算法和成员函数通常并不是是一样的。

  18. 条款46:靠率使用函数对象代替函数作算法的参数

    sort(vec.begin(), vec.end(), greater<int>());//要加括号

    sort(vec.begin(), vec.end(), comp); //函数指针不加括号

    把STL函数对象——化装成函数的对象——传递给算法所产生的代码一般比传递真的函数高效。在让你的代码可以编译方面,它们也更稳健(有些情况下函数指针不能编译,但是函数对象能够编译)。

    这个行为的解释很简单:内联。如果一个函数对象的operator()函数被声明为内联(不管显式地通过inline或者

    隐式地通过定义在它的类定义中),编译器就可以获得那个函数的函数体,而且大部分编译器喜欢在调用算

    法的模板实例化时内联那个函数。所以有函数对象时没有一次函数调用。但所有的C++“开销”都在编译期被吸收。

    当我们试图把一个函数作为参数时,编译器默默地把函数转化为一个指向那个函数的指针。编译器产生一个间接函数调用——通过指针调用。大部分编译器不会试图去内联通过函数指针调用的函数

  19. 条款47:避免产生只写代码

    代码的读比写更经常,这是软件工程的真理。不能读和理解

    的软件不能被维护,不能维护的软件几乎没有不值得拥有。你用STL越多,你会感到它越来越舒适,而且你

    会越来越多的使用嵌套函数调用和即时(on the fly)建立函数对象。这没有什么错的,但永远记住你今天写

    的代码会被某个人——也可能是你——在未来的某一天读到。为那天做准备吧。

  20. 条款48:总是#include适当的头文件

    list在<list>中声明等。<set>声明了set和multiset,<map>声明了map和multimap。

    特殊的迭代器,包括istream_iterators和istreambuf_iterators(参见条款29),在<iterator>中声明

    标准仿函数(比如less<T>)和仿函数适配器(比如not1、bind2nd)在<functional>中声明。

  21. 条款49:学习破解有关STL的编译器诊断信息

    string不是一个类。basic_string才是一个STL中的sequence container。string只是宏定义。

    typedef basic_string<char, char_traits<char>, allocator<char> >  string;

    typedef basic_string<wchar_t, char_traits<wchar_t>,allocator<wchar_t> >  wstring;

    所以string和wstring就没有特别之处了。



转载于:https://my.oschina.net/zengjs275/blog/655323

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值