使用标准模板库中的vector时需要注意的地方

来源:互联网 发布:端口号的作用是什么 编辑:程序博客网 时间:2024/05/18 03:25

STL中的vector用起来很方便,但是对其正确使用是使用方便的前提。
根据C++的发明者Bjarne Stroustrup的忠告自我总结一下

vector的原型 vector<class T, class A=allocator<T>> class std::vector

vector提供的资源
A  vector是给程序员提供容器,可以容纳其模板类的数组;
B  vector的可以动态分配内存以适应其元素个数的改变;
C  vector提供了对其元素的高效的随机访问性能;
D  vector里的元素是其源对象的副本

1 决不要另行定义标准库的功能
2 STL中的每个容器(包括vector)都提供了一个名为iterator的迭代器用于对元素的访问,这个迭代器可以用于修改元素,另外还提供了一个const_iterator的迭代器用于不加修改的元素的访问。迭代器可以看作是指向容器元素的指针,因此,除非另有原因,应该使用更安全的const_iterator迭代器
3 访问元素有两种方法,操作符号[ ]和函数at( )[ ]不带检查而at( )要做范围检查并在下标越界时抛出out_of_range异常。对于已经做过范围检查的访问,可以用[ ]得到高效率的访问,若不清楚范围,则最好用at( )
3 构造函数析构函数和复制操作:
  3.1 构造函数:构造函数通过使用模板类型的默认构造函数创建一个对象副本;
    注意:静态对象(全局对象,名字空间对象,局部静态对象)将自动初始化为适当的0,而局部对象和在自由存储区中建立的对象(自动对象,动态对象,堆对象)不会做自动初始化。
   在某个类型没有默认构造函数时,在没有显式为每个元素提供值的情况下,我们就不能创建以这个类型为元素的向量。
   默认构造函数就是调用时不必提供参数的构造函数,如果用户自己声明了一个默认构造函数,编译器就会使用它,否则,如果有必要,而且用户没有声明其它的构造函数,编译器就会设法去生成一个。编译器生成的默认构造函数将隐式为类类型的成员和它的基类调用有关的默认构造函数。
    由于复制构造函数和复制赋值运算符拷贝vector的所有元素,对于有很多元素的vector而言,这种操作的代价可能很高,所以vector通常采用引用传递。即使用void fun(vector<int>&)和void fun(const vecotr<int>)不使用void fun(vector<int>)这种做法。
   赋值函数assign():对于多参数构造函数,vector提供了一些assign函数以实现其功能,如果要采用一个默认值或者需要提供一个范围中的一些值时,就需要采用assign()函数,如:
class Book {
  //....
}
void f(vector<Num>&vn, vector<char>&vc, vector<Book>&vb, list<Book>&lb)
{
    vn.assign(10,Num(0)); //用由10个Num(0)的副本构成的向量来给vn复制
    char s[]="literal";
    vc.assign(s, &s[sizeof(s)-1]); //用串"literal"给vc赋值
    vb.assign(lb.begin(), lb.end()); //用表lb的元素给vb赋值
}
注意:赋值将完全改变一个向量里的全部元素,所有的老元素都被删除,新元素插入,在赋值过后,vector的大小就是所赋值的新元素的个数。使用assign()函数可以用任何向量类型的序列对vector进行初始化或者类似的以任何这样的序列给向量赋值。重要的是,我们并没有引进大量的构造函数或者转换函数。
    assign所做的事情也可以间接完成,可以首先创建一个适当的vector,而后再给它赋值
    void f(vector<Book>vh, list<Book>&lb)
    {
       vector<Book>vt(lb.begin(), lb.end());
       vh=vt;
    }
  但是,这样做既丑陋又低效。
  3.2 析构函数:vector将使用其类型的析构函数,因此,正确的析构函数是使用vector工作良好的一个前提条件。
  4 堆栈操作:vector经常用来做堆栈,因此引入了 push_back()和pop_back(),back()等函数,但pop_back并不返回值。
  5 表操作: insert()
  6 使用迭代器类型而不要采用索引元素的指针
  7 多用容器和push_back()或resize(),少用数组和realloc(),
      resize(n, val)  //将vector的尺寸改变为容纳n个元素,增加的元素用val初始化:
      reserve(n) //做出总数为n个元素的空位,不初始化。

  8 当vector改变大小后,不要使用指向其中的迭代器。其原因是vector在做resize等操作时元素可能会因内存分配而被移动到别的地方,从而使得你保存的那些指针是非法的。
  9 利用reserve()避免迭代器非法。在需要的时候,利用reserve()以使得执行情况更容易预期。
 10 若能预期,在vector创建时分配大小