stl的一些注意地方

容器是用来存储和组织其他对象的对象

头文件内容
vector表示一个必要时可自动增加容量的数组
array数组容器优于vector<>的一个优点是,它可以完全在栈上分配,而vector<>总是需要访问堆
deque增加了向容器开头添加元素的能力
forward_list单向链表,以前向方式处理链表中的元素,就比List快
mapmap<K,T>是关联容器,用关联键(类型为k)存储T类型的每个元素
unordered_map类似于map但是该容器中的键/对象对没有特定的顺序
set是一个映射,各对象作为自身的键,所有对象必须唯一,并且无法在集合中修改对象
unordered_set类似于set,但元素进行无序排列
bitset定义表示固定位数的bitset<T>类模板,通常用来存储表示一组状态或条件的标志

大多数STL容器都会自动增大其容量来容纳所存储的元素。这些容器的附加内存用一个名为分配器的对象来提供,分配器一般会在需要时分配堆上的内存,也可以通过一个额外的类型形参,提供自己的分配器类型。

例如,创建向量的vector<T>模板实际上是一个vector<T,A<T>>模板,第二个类型的形参默认分配器类型是allocator<T>

容器适配器是包装了现有STL容器类的模板类,如队列,栈

迭代器对象的行为和指针相似,它对于访问除容器适配器定义内容之外所有STL容器的内容非常重要,容器适配器不支持迭代器

得到的迭代器类型取决于使用的容器的种类

智能指针用于动态分配内存对象

unique_ptr<T>类型定义了一个对象,用来存储唯一对象的指针

shared_ptr<T>类型指针可以同时有多个shared_ptr对象指向相同的对象,并且引用该对象的shared_ptr对象数量会记录下来,指向同一个对象的所有shared_ptr对象必须在他们所指向的对象删除之前删除,当最后一个指向给定对象的shared_ptr对象删除后,它指向的对象才能删除且释放其内存

weak_ptr<T>类型存储了一个连接到shared_ptr的指针,weak_ptr<T>不会递增或递减所链接shared_ptr的引用数,所以可以在引用它的最后一个shared_ptr删除之前,不会删除对象,释放其内存。weak_ptr对象就是为避免引用循环问题而设计的,使用weak_ptr对象指向一个shard_ptr对象所指向的对象,就可以避免引用循环。只需要删除shared_ptr对象,它指向的对象就能删除,接着与shared_ptr相关的weak_ptr对象就变为无效。

make_unique<T>()函数模板在堆上创建了一个新的T对象,在创建一个指向T对象的unique_ptr<T>对象如:

auto pBox=std::make_unique<CBox>(2.0,3.0,4.0);

同理,最好使用make_shared<T>()函数在堆上创建一个T类型的对象,再返回一个指向它的shared_ptr<T>对象,因为内存分配更加高效。

有时需要访问智能指针包含的指针:这称为裸指针,调用智能指针对象的get()成员会返回裸指针,调用reset()会把裸指针重置空

对智能指针的转化需要使用static_pointer_cast,dynameic_pointer_cast和const_pointer_cast,在memory头文件中定义。

算法在algorithm和numeric头文件中定义。

函数适配器是允许合并函数对象以产生一个更复杂的函数对象的函数模板

vector的函数:capacity()返回当前容量,max_size()返回矢量中元素的最大可能数目。resize()可以增加或减小矢量大小,front()返回第一个元素,back()返回最后一个元素,pop_back()删除最后一个元素,clear()删除所有元素,insert()插入新元素,emplace()和emplace_back用于在矢量中插入对象时就地创建它,erase()可以删除矢量中任何位置的一个或多个元素。assign用另一序列替换一个矢量中的全部内容,或者用给定数量的对象实例替换矢量内容。

functional头文件定义比较谓词的完整函数对象集合,包括:less<T> less_equal<T> equal<T> greater_equal<T> greater<T>,用作sort函数的第三个参数

数组容器的表达方式

template<class T,size_t N>
void listValues(const array<T,N>& data)
{
  ..
}

使用numeric头文件定义的accumulate()模板函数可以求数组之和,第一个参数为开始位置,第二结束位置,第三个相加后赋予的值。

双端队列的前段添加元素的函数为push_front(),删除第一个元素为pop_front

列表的begin()和end()函数返回的是迭代器是双向迭代器,只能使用递增或递减运算符修改双向迭代器的值。

列表函数advance()函数来递增迭代器,将第一个实参指定的迭代器递增第二个实参指定的次数。emplace()在迭代器指定的 上构建一个元素,emplace_front()在列表开头构建一个元素,emplace_back()在列表结尾构建一个元素。remove()函数从列表中删除匹配特定值的元素。unique()函数将消除列表中相邻的重复元素,如果先排序,即可确保所有元素的唯一。splice()函数可以删除一个列表的全部或一部分,并将它插到另一个列表中,第一个实参为迭代器,指定插入元素的位置,第二个是插入的元素来自的列表,将会删除原来的位置的元素。merge()函数删除作为一个实参提供的列表中的元素,并将它们插入调用该函数的列表中,在调用之前,2个列表都必须适当地排序。例如:

list<int> numbers{1,2,3};//1 2 3
list<int> values{2,3,4,5,6,7,8};//2 3 4 5 6 7 8
numbers.merge(values);//1 2 2 3 3 4 5 6 7 8

remove_if()函数基于应用一元谓词的结果来删除列表中的元素。一元谓词是一个应用到单个实参的函数对象,它返回一个bool值true或false,如果向一个元素应用谓词的结果是true,就会从列表删除该元素。通常我们会定义自己的谓词。基类模板如下:

template<class _Arg,class _Result>
struct unary_function
{
  typedef _Arg argument_type;
  typedef _Result result_type;
};

template<class T>class is_negative:public std::unary_function<T,bool>
{
   public:
    result_type operator()(argument_type& value)
{
  return value<0;
 }
};

forward_list,每个元素都包含指向下一个元素的指针,只能向前遍历元素。before_begin()函数返回一个迭代器,指向第一个元素前面的位置,distance()返回元素个数。forward_list<T>容器提供的性能比List<t>容器好得多,只有一个链接要维护,使其操作起来更快,且不需要跟踪元素的个数。

priority_queue<t>容器是一个队列,它的顶部总是具有最大或最高优先级的元素,不过优先级队列不能访问队列后端的元素,只能访问前端的元素。

tuple<>类模板定义在tuple头文件中国,此模板对于array<>容器是一个有用的辅助,tuple<>对象封装了很多不同的项,这些项可以具有不同的类型。例子如下:

using Record=std::tuple<int,std::string,std::string,int>

std::array<Record,5>personal{Record{1001,"joan","jetson",35},
Record{1002,"jim","jones",26},
Record{1003,"june","jello",31},
Record{1004,"jack","jester",39}};

要访问元祖中的字段,需要使用get()模板函数,注意get()函数模板的类型形参必须是一个编译时常量。

关联容器(如map<K,T>)最重要的特性是无须搜索就可以检索特定的对象,关联容器内T类型对象的位置由于对象一起提供的类型为K的键确定,因此只要提供适当的键,就可以快速地检索任何对象。当创建map<K,T>容器时,K是键的类型,用于存储T类型的关联对象,键/对象对会存储为pair<K,T>类型的对象,pair<K,T>在utility头文件中定义。可以通过成员first和second访问一个对中的元素。.first为键,.second为对象。insert()函数返回的值也是一个对,对中第一个对象是迭代器,第二个对象是bool类型值,成功为true,失败为false;

iterator头文件定义流迭代器的几个模板,用于将数据从源传到目的地,流迭代器作为指向输入流或输出流的指针,可以在流和任何使用迭代器的源或目的地之间传输数据,如算法。

std::istream_iterator<int> numbersInput{std::cin};//创建输入流迭代器

sstream头文件定义了basic_istringstream<T>模板,这个模板定义了可以访问流缓冲区中的数据对象类型。

std::string data{"2.4 2.5 3.6 2.1 6.7 6.8 94 95 1.1 1.4 32"};
std::istringstream input{data};
std::istream_iterator<double>begin (input),end;//由于从string对象data中创建istringstream对象,因为可以像流一样从data中读取数据。

copy函数将迭代之间指定的实参复制到输出流迭代器中。如:

std::ostream_iterator<int> out{std::cout};
int data[]{1,2,3,4,5,6,7,8,9};
std::copy(std::cbegin(data),std::cend(data),out);

not2<>()模板函数,它创建一个二元谓词,它是传递为实参的函数对象定义的二元谓词的负值。例如,not2(less<int>())创建一个二元谓词来比较Int类型的对象,如果左操作数不小于右操作数,则返回true。

函数对象模板说明
plus<T>计算两个T类型元素的和
minus<T>通过从第一个操作数中减去第二个操作数来计算他们之间的差
Multiplies<T>计算两个T类型元素的积
divides<T>用第一个T类型操作数除以第二个T类型操作数
modulus<T>计算第一个操作数除以第二个操作数后的余数
negate<T>返回T类型操作数的负值
上述的这些都是通过transform来使用的

transform的这个版本将一元函数f应用到迭代器begin,end指定的范围中的所有元素,并从迭代器result指定的位置开始存储结果

OutputIterator transform(InputIterator begin,InputIterator end,
OutputIterator result,UnaryFunction f)

由begin1和end1指定的范围表示最后一个实参指定的二元函数f的左操作数集合表示右操作数的范围从begin2迭代器指定的位置开始,这个范围不需要提供end迭代器,因为这个范围的元素数量必须与begin1和end1指定的范围中的元素个数相同,结果将从resut迭代器位置开始存储在这个范围内,如果希望结果存储回该范围中,result迭代器可以与begin1相同,但是它一定不能是begin1和end1之间的其他任何位置。

transform(InputIterator1,begin1,InputIterator end1,InputIterator2 begin2,OutputIterator result,BinaryFunction f)

静态断言可以在编译期间检测用法错误,形式如下:

static_assert(constant_expression,string_literal);

constant_expression,应的到一个可转换为bool类型的值,如果结果是true,就什么都不做,如果它是false,编译器就显示字符

λ表达式定义一个没有名称,也不需要显式类定义的函数对象,λ表达式作为一种手段,用来将函数作为实参传递到另一个函数。λ形参有几个限制,不能指定λ表达式形参的默认值,形参列表的长度不能变,默认返回类型会返回值的类型,也可指定如:

[](double x)->double{return x*x*x;}

f方括号之间是=,则λ主体可以按值访问封闭作用域中的所有自动变量,即变量值可用在λ,但不会修改原始的变量,如果是&引用,则可以访问加修改。按值访问中,想修改外面的变量需要加上mutable。

可以将无状态的λ赋予函数指针变量,这样就给λ表达式指定了名称,如

auto sum=[](int a,int b){return a+b;};
cout<<sum(5,10);//直接调用


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章