C++Primer 第九章

时间:2023-03-09 13:38:49
C++Primer 第九章
//1.vector:可变大小数组。支持快速随机访问,在尾部之外的位置插入或删除元素可能很慢。注意点:不要在vector中存放bool类型,vector<bool>并不是一个容器,其实现方式类似于位域,不能对其元素取地址或者建立引用,因为其元素仅仅是一个比特。然而deque<bool>却是一个容器。
// deque:双端队列。支持快速随机访问,在头尾插入或删除元素很快。
// list:双向链表。只支持双向顺序访问。任何位置插入或删除元素都很快。
// forward_list:单向链表。只支持单向顺序访问。在任何位置插入或删除元素都很快。
// string:与vector相似的容器,专门用于保存字符。支持随机访问。在尾部插入或删除元素很快。 //2.通常情况选择vector,当不确定用哪种容器的时候,那么就只使用迭代器操作,这样在更换容器的时候会很方便。 //3.如果容器元素类型没有默认构造函数,当为此容器提供了大小参数外,还必须提供一个显示的元素初始值(这个显示的元素初始值必须能被构造成容器的元素类型)。
class CTest
{
public:
CTest(int i) : value(i){}
private:
int value;
}; vector<CTest> vecTest(2, 10); //vecTest = [2]({value=10 },{value=10 })
vector<CTest> vecTest1(2); //错误,没有传入初始值
vector<CTest> vecTest2; //正确 //4.公用容器的类型别名操作:
// iterator:此容器的迭代器类型
// const_iterator:只读迭代器类型
// size_type:无符号整形,足够保存此种容器类型最大可能容器的大小。32位程序下,为4字节,64位程序下为8字节。
// difference_type:带符号整形,足够保存两个迭代器之间的距离。32位程序下,为4字节,64位程序下为8字节。在32位下应用程序可使用的内存小于2G,也就是小于int的最大值。
// value_type:容器所存元素类型。
// reference:容器所存元素的引用类型。等价于value_type&
// const_reference:容器所存元素的常量引用类型。等价于const value_type& //5.反向迭代器与正向迭代器相比,各种操作的含义均发生颠倒。例如++会得到反向迭代器的上一个元素。 //6.可以将A容器中的元素拷贝到B容器中,只要A容器的元素类型能转换为B容器的元素类型
list<double> listDouble;
listDouble.emplace_back(1.1);
listDouble.emplace_back(2.2);
vector<int> vecInt(listDouble.begin(), listDouble.end()); //vecInt = [2](1,2)
vector<int> vecInt1;
vecInt1.assign(listDouble.begin(), listDouble.end()); //vecInt1 = [2](1,2)
// 注意点:容器的assign操作还有一种用法:vecInt1.assign(2,1); //vecInt1 = [2](1,1) //7.当改变了容器的元素后,注意指向容器元素的迭代器、指针、引用可能会失效。比如容器的赋值操作就会导致上述结果。在每次改变容器的操作后都应该重新定位迭代器、指针、引用。 //8.容器的emplace系列的函数,使用给定的参数创建一个元素(如果不是内置类型则调用其构造函数),而push_back或者push_front函数则是按值拷贝一个元素(不会主动调用元素的构造函数)。insert在这方面的表现和push_back系列函数一致。
vector<unique_ptr<char[]>> vecStr;
vecStr.emplace_back(new char[10]()); //合法
vecStr.push_back(new char[10]()); //非法
vecStr.insert(vecStr.begin(), new char[10]()); //vs2010下虽然合法,但是从语法上来说,这句话是错误的。

#include <vector>
  using std::vector;

class CTest
  {
  public:
  explicit CTest(int value)
  {
      value0 = value;
      printf("0 ");
  }

CTest(const CTest& Test)
  {
      value0 = Test.value0;
      printf("1 ");
  }

private:
      int value0;
  };

int _tmain(int argc, _TCHAR* argv[])
  {
      vector<CTest> vecTest(1, CTest(0));//输出0 1    这是先进行构造然后将其拷贝进vector

CTest Test(3);              //输出0
      vecTest.push_back(Test);    //输出1 1    这是先拷贝构造然后将其拷贝进vector

//vecTest.push_back(1);     //由于构造函数是explicit的,所以这句话非法

vecTest.emplace_back(2);    //输出1 1 0  前面两个1是因为vector发生内存重新分配,所以拷贝了原先的2个元素,最后一个0是直接构造
      printf("s");

    //由上述代码得出结论,emplace系列函数比push系列函数的效率,在理论上高点
  }

//9.容器中不能存放元素的引用。

//10.一般容器都提供了front()和back()成员函数,分别用于返回首尾元素的引用。一般容器提供了at()成员函数,用法类似于下标运算符,但是前者多了判断下标是否越界的功能,若越界则会抛出out_of_range异常。

//11.单向链表forward_list的插入和删除操作:insert_after,emplace_after,erase_after。由于单向链表可以方便的得到其下一个成员而无法得到其上一个成员,所以其插入和删除操作不同于其他容器,相应的before_begin返回单向链表的首前迭代器。

//12.利用resize成员函数可以很方便的改变容器的大小,支持为要新添加的元素传入初始化参数。
// 利用reserve成员函,来分配至少能容纳指定个元素的内存空间。注意点:这里仅是内存分配而不涉及元素构造,此函数不会改变容器的size,但是会改变容器的capacity。 //13.string类的常用操作:
// c_str():返回const char*类型的字符串
// substr:从指定的string中的指定位置返回指定长度的string
// find:查找指定序列在指定位置后第一次出现的位置
// rfind:查找指定序列在指定位置后最后一次出现的位置
// find_first_of:查找指定序列在指定位置后第一次出现序列中的元素的位置
// find_last_of:查找指定序列在指定位置后最后一次出现序列中的元素的位置
// find_first_not_of:在指定位置后查找第一个不在指定序列中的元素的位置
// find_last_not_of:在指定位置后查找最后一个不在指定序列中的元素的位置
// replace:将指定的序列中的元素替换为另一个指定序列中的元素 //14.容器适配器:一个容器适配器能接受一种已有的容器类型,使其行为看起来像一种不同的类型。
// stack:定义在头文件stack中,在栈顶进行操作。
// 支持操作:pop(),push(),emplace(),top()
// 默认使用deque实现,也可以在list或者vector之上实现。
// queue:定义在头文件queue中,其元素为先进先出。进入的元素放置在队尾,在队首进行删除。
// 支持操作:pop(),front(),back(),push(),emplace()
// 默认使用deque实现,可以用list和vector实现。
// priority_queue:定义在头文件queue中。允许我们为队列中的元素建立优先级。默认使用<来确定相对优先级(由大到小排列)。
// 支持操作:pop(),push(),emplace(),top()。注意:top()返回priority_queue中优先级最高的元素。支持随机访问。
// 默认使用vector实现,也可以用deque实现
stack<int, vector<int>> staInt; //使用非默认容器来构造容器适配器。 //15.
// begin(),end() ++ ->
// begin() end()
// | |
// v v
// AAAAAAAAAAAAAAAAA
// ^ ^
// | |
// rend() rbegin()
// rend(), rbegin() -- ->