![](https://img-blog.csdnimg.cn/20201014180756925.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
STL
一只牛_007
这个作者很懒,什么都没留下…
展开
-
18.了解各种与排序有关的选择
排序算法有如下:sort、stable_sort partial_sort、无对应的稳定排序算法 nth_element、无对应的稳定排序算法 partition、stable_partitionsort、stable_sort、partitial_sort、nth_element算法都要求随机访问迭代器,所以这些算法都只能被应用于vector、string、deque和数组。对标准关联容器中的元素进行排序并没有实际意义,因为这样的容器总是使用比较函数来维护内部元素的有效性。list是唯一需要排原创 2021-06-26 15:09:06 · 88 阅读 · 0 评论 -
17.容器的成员函数优先于同名的算法
有些STL 容器提供了一些与算法同名的成员函数。大多数情况下,应该使用这些成员函数,而不是相应的STL算法。 有两个理由:成员函数往往速度快。 成员函数通常与容器结合地更紧密,这是算法所不能比的。set容器的find成员函数以对数时间运行,而find算法以线性时间运行。效率并不是find成员函数和find算法之间的唯一差别。STL算法以相同性而判断两个对象是否具有相同的值,而关联容器使用等价性来进行它们的"相同性"测试。因此,在使用关联容器的时候,应该优先考虑成员函数形式的find、count、原创 2021-06-26 14:56:42 · 154 阅读 · 0 评论 -
16.算法调用优先于手写的循环
STL算法涉及面很广,这意味着你本该编写循环来完成的任务也可以用STL算法来完成。例如,有一个Widget类:class Widget{public: ... void redraw() const; ...};当你想在一个包含Widget的list中调用所有成员的Widget对象,可以用一个循环来完成,std::list<Widget> datas;...for (auto iter = datas.begin(); iter != da...原创 2021-06-26 14:53:01 · 109 阅读 · 0 评论 -
15.确保“lessT“与“operator小于“具有相同的语义
Widget类定义如下:class Widget{public: ... size_t weight() const; size_t maSpeed() const; ...}通常情况下,按重量对Widget进行排序是最自然的方式。Widget的operator < 反映了这一点。bool operator < (const Widget& lhs, const Widget& rhs){ return lhs.we...原创 2021-06-26 14:42:31 · 136 阅读 · 0 评论 -
14.理解copy_if算法的正确实现
STL中有11个算法名字包含"copy":copycopy_backwardreplace_copyreverse_copyreplace_copy_ifunique_copyremove_copyrotate_copyremove_copy_ifpartial_sort_copyunitialized_copy但是STL中却不包括copy_if的实现,如果需要它,必须自己实现。下面是copy_if的正确实现:template<typename InputIterat原创 2021-06-26 14:25:03 · 173 阅读 · 0 评论 -
13.transform确保目标空间足够大
以一个例子开始讨论:int transmogrify(int x); // 该函数更具x生成一个新的值std::vector<int> values;...std::list<int> results;std::transform(values.begin(), values.end(), results.end(), transmogrify); //transform将values中的每个元素作为参数,调用transmogrify后将返回值写入到results.原创 2021-06-26 14:03:29 · 105 阅读 · 0 评论 -
12.当效率至关重要时,请在map::operator[]与map::insert之间谨慎作出选择
有一个widget类如下:class Widget{public: Widget(); Widget(double weight); Widget& operator = (double weight);}使用如下:std::map<int, Widget> datas; // 语句1datas[1] = 1.50; // 语句2调用语句2之前,datas为空。因此,语句2等同于先默认构造一对象,然后再对其进行赋值。auto i...原创 2021-06-26 13:50:28 · 190 阅读 · 0 评论 -
11.考虑用排序的vector替代关联容器
当想到排序时,第一个想到的是关联容器set、muliset、map、multimap, 它们的底层实现为红黑树,查找的时间复杂度为O(log(n))。也可以使用哈希容器unordered_set、unorderd_multiset、unordered_map、unordered_multimap,它们的底层实现为哈希表,查找的时间复杂度为常数时间复杂度。关联容器使用的红黑树,优化了插入、查找、删除等操作,使它们均为对数时间复杂度。所以对于各种情况下的操作,它的查找性能都会比较稳定。但是,对于容器,如原创 2021-06-26 13:45:07 · 107 阅读 · 0 评论 -
9.为包含指针的关联容器指定比较类型
有如下代码:std::set<std::string*> datas;datas.insert(new std::string("Anteater"));datas.insert(new std::string("Wombat"));datas.insert(new std::string("Lemur"));datas.insert(new std::string("Penguin"));打印datas中的内容:for (auto* pData : datas){.原创 2021-06-25 13:33:53 · 90 阅读 · 0 评论 -
8.了解如何把vector和string数据传给旧的API
vector和string都是使用连续内存来存储数据,可以类似于普通数组进行处理。std::vector<int> datas;std::string strData;获取vector的首个元素的指针:&datas[0]&(*datas.begin())但必须确保容器非空,使用前最好调用empty()。C++11中,可以使用成员函数data()。其函数声明为:value_type* data() noexcept;const value_t.原创 2021-06-25 13:26:31 · 105 阅读 · 0 评论 -
7.使用reserve避免不必要的内存分配
vector、string可以自动增长来容纳更多的元素。每当需要更多空间时,就调用与realloc类似的操作。realloc操作分为4个部分:分配一块大小为当前容量的某个倍数的新内存。在大多数实现中,vector和string的容量每次以2的倍数增长,即每当容器需要扩张是,它们的容量即加倍。 把容器的所有元素从旧的内存中拷贝到新的内存中。 析构掉内存中的对象。 释放旧内存。涉及到内存的分配、释放、拷贝、析构等步骤,这个过程将非常耗时。reserve()可以使重新分配的次数降低,只有当元素原创 2021-06-25 13:22:37 · 264 阅读 · 0 评论 -
6.切勿对STL容器的线程安全性有不切实际的依赖
STL自身对多线程的支持非常有限。对于STL,你能期望的是:多个线程读是安全的。 多个线程对不同的容器做写入操作时安全的。在需要修改STL容器或这调用STL算法时需要自己加锁。为了实现异常安全,最好不要手动加锁解锁,多使用RAII。例如多使用std::lock_guard(),std::lock_guard是RAII模板类的简单实现,功能简单。std::lock_guard 在构造函数中进行加锁,析构函数中进行解锁,即使遭遇异常,依旧可以保证锁被释放。C++保证,如果有异常被抛出,局部对象原创 2021-06-25 10:27:12 · 132 阅读 · 0 评论 -
5.慎重选择删除元素的方法
有一容器Container datas;删除所有值为1000的元素对于序列容器(vector、deque、string):最好的办法为调用惯用法erase-remove。// destData为要删除的元素datas.erase(std::remove(datas.begin(), datas.end(), destData), datas.end());对于list:最好的办法是直接调用成员函数remove()。datas.remove(destData);对于关联容器(se原创 2021-06-25 10:23:01 · 111 阅读 · 0 评论 -
4.如果容器中包含了通过new操作创建的指针,切记在容器对象析构前将指针delete掉
容器很聪明,能够做很多事情。容器析构时,会调用元素的析构函数。但是,如果是元素为指针,会出现内存泄漏。...std::vector<Widget*> datas;for (int idx = 0; idx < 100; ++idx) datas.push_back(new Widget);...datas析构时,不会为其指针元素调用delete,所以你必须自己在容器析构时手动delete。...for (auto* pWidget : datas) ...原创 2021-06-25 10:07:26 · 227 阅读 · 0 评论 -
3.调用empty而不是检查size()是否为0
检查容器是否为空,一律都使用成员函数empty()而非size()。因为empty()总是常数复杂度,而size()却不都是,比如list就不是。如果list要使size()为常量复杂度,就必须保存元素的数量。涉及到会导致元素数量变化的成员函数,就需要知道新增或减少元素的个数(通过遍历),然后更新元素数量。这会使该成员函数为线性复杂度。而list的成员函数splice()被设计为常数复杂度,不知道新增元素的个数。splice()和size()两者的常量复杂度不可兼得,二者只能得一。STL选择spl原创 2021-06-25 09:57:56 · 116 阅读 · 0 评论 -
2.区间成员函数优先于与之对应的单元素成员函数
案例1:v1、v2两个vector, 将v2后半部分内容赋给v1区间成员函数版本:std::vector<int> v1;...std::vector<int> v2;...v1.assign(v2.begin() + v2.size() / 2, v2.end());单元素成员版本:std::vector<int> v1;...std::vector<int> v2;...v1.clear();for (auto it.原创 2021-06-25 09:56:57 · 96 阅读 · 0 评论 -
1.确保容器中的对象拷贝正确而高效
向容器中插入或者返回对象,或者其他类型的操作(remove unique)都会涉及到对象的拷贝。这也是为什么要求容器的元素类必须支持拷贝(拷贝构造函数, 拷贝复制函数)的原因。以类Widget为例 :class Widget{public: ... Widget(const Widget&); Widget& operator = (const Widget&); ... };如果大量向容器中插入元素,同时拷贝构造函数的开...原创 2021-06-25 09:54:09 · 126 阅读 · 0 评论 -
STL 容器迭代器失效总结
总结常见的序列容器(vector、deque、list)和关联容器(set、multiset、map、multimap)的迭代器失效问题。原迭代器指的是进行操作之前保存的迭代器,包括begin()、end()以及其他位置的迭代器。vector:成员函数push_back():会在容器末尾添加一个元素。如果容器有剩余空间(capacity() > size()),则直接添加新元素到容器尾部。此时,原迭代器中end()会失效,其他的都不会失效。否则,会导致容器重新分配内存,然后将数据从原内存复原创 2021-06-25 09:34:19 · 423 阅读 · 0 评论