C++Primer读书笔记:第3章 标准库类型

  通常,头文件中应该只定义确定必要的东西请养成这个习惯

标准库string类型

  几种初始化string对象的方式

 
    
  string s1;       // 默认构造函数,s1为空串
  string s2(s1);    // s2初始化为s1的一个副本
  string s3( " value " ); // s3初始化为一个字符串字面值副本
  string s4(n, ' c ' );  // s4初始化为字符'c'的n个副本

  字符串字面值标准库string类型不是同一种类型

  由于getline函数返回时丢弃换行符,换行符将不会存储在string对象中。


  string对象的操作

 
    
  s.empty()   // 如果s为空串,则返回true,否则返回false
  s.size()   // 返回s中字符的个数
  s[n]      // 返回s中位置为n的字符,位置从0开始计数
  ...

 

string::size_type类型

  它定义为与unsigned型具有相同的含义,而且可以保证足够大能够存储任意string对象的长度。

  任何存储stringsize操作结果的变量必须string::size_type类型。特别重要的是,不要size的返回值赋给一个int变量。

  

和字符串字面值的连接

  当进行string对象和字符串字面值混合连接操作时,+操作符左右操作数必须至少有一个是string类型的:

 
     
  string s1 = " hello " ;         // no punctuation
  string s2 = " world " ;
  string s3 = s1 + " , " ;        // ok: adding a string and a literal
  string s4 = " hello " + " , " ;     // error: no string operand
  string s5 = s1 + " , " + " world " ;  // ok: each + has string operand
  string s6 = " hello " + " , " + s2;  // error: can't add string literals

 

计算下标值

  任何可产生整型值的表达式都可用作下标操作符的索引。例如,假设someval和someotherval是两个整型对象,可以这样写:

 
    
  str[someotherval * someval] = someval;

  在定义用作索引的变量时,string对象的索引变量最好也用string::size_type


 string对象中字符的处理

  cctype定义的函数

 
    
  isalnum(c) isalpha(c) iscntrl(c) isdigit(c)
  isgraph(c) islower(c) isprint(c) ispunct(c)
  isspace(c) isupper(c) isxdigit(c)
  tolower(c) toupper(c)

 

建议:采用C标准库头文件的C++版本

  C标准库头文件命名形式为name.h,而C++版本则命名为cname,cnamename.h文件的内容是一样的,只是采用了更适合C++程序的形式。特别地,cname头文件中定义的名字都定义在命名空间std内,而.h版本中的名字却不是这样。

  通常,C++程序中应采用cname这种头文件的版本,而不采用name.h版本,这样,标准库中的名字在命名空间std中保持一致。使用.h版本会给程序员带来负担,因为他们必须记得哪些标准库名字是从C继承来的,哪些是C++所特有的


标准库vector类型

  vector不是一种数据类型,而只是一个类模版,可以用来定义任意多种数据类型。vector类型的每一种都指定了其保存元素的类型。因此,vector<int>和vector<string>都是数据类型

vector对象的定义和初始化

  几种初始化vector对象的方式

 
    
  vector < T > v1;       // vector保存类型为T的对象。默认构造函数v1为空
  vector < T > v2(v1);    // v2是v1的一个副本
  vector < T > v3(n, i);   // v3包含n个值为i的元素
  vector < T > v4(n);     // v4含有值初始化的元素的n个副本

  虽然可以对给定元素个数的vector对象预先分配内存,但更有效的方法是先初始化一个vector对象,然后再动态地增加元素

 

vector对象的操作

  vector操作

 
    
  v.empty() v.size() v.push_back(t) v[n]

vector的下标操作

  下例使用for循环把vector中的每个元素值都重置为0:

 
    
  // reset the elements in the vector to zero
  for (vector < int > ::size_type ix = 0 ; ix != ivec.size(); ++ ix)
   ivec[ix]
= 0 ;

 

关键概念:安全的泛型编程

  C++程序员习惯于优先选用!=而不是<来编写循环判断条件。调用size成员函数而不保存它的返回值,反映了一种良好的编程习惯。在C++中,有的数据结构(如vector)可以动态增长。上例中循环仅需要读取元素,而不需要增加新的元素。但是,循环可以容易地增加新元素,如果确实增加了新元素的话,那么测试已保存的size值作为循环的结束条件就会有问题,因为没有将新加入的元素计算在内。所以我们倾向于在每次循环中测试size的当前值,而不是在进入循环前,存储size值的副本。

 

下标操作不添加元素

  初学C++的程序员可能会认为vector的下标操作可以添加元素,其实不然:

 
    
  vector < int > ivec;   // empty vector
  for (vector < int > ::size_type ix = 0 ; ix != 10 ; ++ ix)
   ivec[ix]
= ix;  // disaster: ivec has no elements

  这个循环的正确写法应该是:

 
    
  for (vector < int > ::size_type ix = 0 ; ix != 10 ; ++ ix)
   ivec.push_back(ix);
// ok: adds new element with value ix

  必须是已存在的元素才能用下标操作符进行索引。通过下标操作进行赋值时,不会添加任何元素

 

警告:仅能对确知已存在的元素进行下标操作

  对于下标操作符([]操作符)的使用有一点非常重要,就是仅能提取确实已存在的元素,例如:

 
    
  vector<int> ivec;    // empty vector
  cout << ivec[0];     // Error: ivec has no elements!

  vector
<int> ivec2(10); // vector with 10 elements
  cout << ivec[10];    // Error: ivec has elements 0...9

 

迭代器简介

vector迭代器的自增和解引用运算

  迭代器类型可使用解引用操作符(*操作符)来访问迭代器所指向的元素:

 
    
  * iter = 0 ;

解引用操作符返回迭代器当前所指向的元素。假设iter指向vector对象ivec的第一个元素,那么*iter和ivec[0]就是指向同一个元素。

  由于end操作返回的迭代器不指向任何元素,因此不能对它进行解引用自增操作


const_iterator

  该类型只能用于读取容器内元素,但不能改变其值。

  如果我们对const_iterator类型解引用时,可以得到一个指向const对象的引用,如同任何常量一样,该对象不能进行重写。

  例:

 
     
  // use const_iterator because we won't change the elements
  for (vector < string > ::const_iterator iter = text.begin();
             iter
!= text.end(); ++ iter)
    cout
<< * iter << endl;   // print each element in text

  for (vector < string > ::const_iterator iter = text.begin();
             iter
!= text.end(); ++ iter)
    
* iter = " " ;         // error: *iter is const

不要把const_iterator对象与constiterator对象混淆起来。声明一个const迭代器时,必须初始化迭代器。一旦被初始化后,就不能改变它的值:

 
    
  vector < int > nums( 10 );     // nums is nonconst
  const vector < int > ::iterator cit = nums.begin();
  * cit = 1 ;            // ok: cit can change its underlying element
  ++ cit;              // error: can't change the value of cit

const_iterator对象可以用于const vector或非const vector,因为不能改写元素值。const迭代器这种类型几乎没什么用处:一旦它被初始化后,只能用它来改写其指向的元素


 
    
  // an iterator that cannot write elements
  vector < int > ::const_iterator
  // an iterator whose value cannot change
  const vector < int > ::iterator

 

迭代器的算术操作

 
    
  iter + n iter - n
  iter1
- iter2   // 该表达式用来计算两个迭代器对象的距离。
        
// 该距离是名为difference_type的signed类型的值
  vector < int > ::iterator mid = vi.begin() + vi.size() / 2 ;

 

标准库bitset类型

  类似于vectorbitset类是一种类模版;而与vector不一样的是bitset类型对象的区别仅在其长度而不在其类型。在定义bitset时,要明确bitset含有多少位,须在尖括号内给出它的长度值:

 
    
  bitset < 32 > bitvec;   // 32 bits, all zero

给出的长度值必须常量表达式

 

初始化bitset对象的方法

 
    
  bitset < n > b;
  bitset
< n > b(u);       // bunsigned long型u的一个副本
  bitset < n > b(s);
  bitset
< n > b(s, pos, n);  // b是s中从位置pos开始的n个位的副本

unsigned值初始化bitset对象

  当用unsigned long值作为bitset对象的初始值时,该值将转化为二进制的位模式。

 
     
  // bitvec1 is smaller than the initializer
  bitset<16> bitvec1(0xffff);  // bits 0...15 are set to 1
  // bitvec2 same size as initializer
  bitset < 32 > bitvec2( 0xffff );   // bits 0...15 are set to 1; 16...31 are 0
  // on a 32-bit machine, bits 0 to 31 initialized from 0xffff
  bitset < 128 > bitvec3( 0xffff );  // bits 32 through 127 initialized to zero

string对象初始化bitset对象

  当用string对象初始化bitset对象时,string对象直接表示为位模式。从string对象读入位集的顺序从右向左

  string对象和bitset对象之间是反向转化的:string对象的最右边字符(即下标最大的那个字符)用来初始化bitset对象的低阶位(即下标为0的位)。当用string对象初始化bitset对象时,记住这一差别很重要

 

bitset对象上的操作

 
    
b.any() b.none() b.count() b.size() b[pos]
b.test(pos) b.
set ()   b. set (pos) b.reset()  b.reset(pos)
b.flip()    b.flip(pos) b.to_ulong() os
<< b

转载于:https://www.cnblogs.com/elite/articles/1901718.html

你可能感兴趣的:(C++Primer读书笔记:第3章 标准库类型)