C++编程思想 第2卷 第7章 通用容器 基本序列容器:vector list deque 向量 已分配存储区溢出的代价


vector从获取到某块存储区开始
就好像一直进行猜测
在放入的对象还没有超出初始存储块所能装载的对象数目的时候
所有的操作都进行得飞快

观察在填充一个vector时发生的事情 有一个Noisy类 
打印出其有关创建 析构 赋值以及拷贝构造的信息

//: C07:Noisy.h
// From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison.
// (c) 1995-2004 MindView, Inc. All Rights Reserved.
// See source code use permissions stated in the file 'License.txt',
// distributed with the code package available at www.MindView.net.
// A class to track various object activities.
#ifndef NOISY_H
#define NOISY_H
#include <iostream>
using std::endl;
using std::cout;
using std::ostream;

class Noisy {
  static long create, assign, copycons, destroy;
  long id;
public:
  Noisy() : id(create++) {
    cout << "d[" << id << "]" << endl;
  }
  Noisy(const Noisy& rv) : id(rv.id) {
    cout << "c[" << id << "]" << endl;
    ++copycons;
  }
  Noisy& operator=(const Noisy& rv) {
    cout << "(" << id << ")=[" << rv.id << "]" << endl;
    id = rv.id;
    ++assign;
    return *this;
  }
  friend bool operator<(const Noisy& lv, const Noisy& rv) {
    return lv.id < rv.id;
  }
  friend bool operator==(const Noisy& lv,const Noisy& rv) {
    return lv.id == rv.id;
  }
  ~Noisy() {
    cout << "~[" << id << "]" << endl;
    ++destroy;
  }
  friend ostream& operator<<(ostream& os, const Noisy& n) {
    return os << n.id;
  }
  friend class NoisyReport;
};

struct NoisyGen {
  Noisy operator()() { return Noisy(); }
};

// A Singleton. Will automatically report the
// statistics as the program terminates:
class NoisyReport {
  static NoisyReport nr;
  NoisyReport() {} // Private constructor
  NoisyReport & operator=(NoisyReport &);  // Disallowed
  NoisyReport(const NoisyReport&);         // Disallowed
public:
  ~NoisyReport() {
    cout << "\n-------------------\n"
         << "Noisy creations: " << Noisy::create
         << "\nCopy-Constructions: " << Noisy::copycons
         << "\nAssignments: " << Noisy::assign
         << "\nDestructions: " << Noisy::destroy << endl;
  }
};
#endif // NOISY_H ///:~
//: C07:Noisy.cpp {O}
// From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison.
// (c) 1995-2004 MindView, Inc. All Rights Reserved.
// See source code use permissions stated in the file 'License.txt',
// distributed with the code package available at www.MindView.net.
#include "Noisy.h"
long Noisy::create = 0, Noisy::assign = 0,
  Noisy::copycons = 0, Noisy::destroy = 0;
NoisyReport NoisyReport::nr;
///:~

每个Noisy对象都有其标识符
并且设置一些静态static变量用来跟踪所有的创建
赋值 拷贝构造和析构操作

NoisyReport是一个单件对象
因为仅仅要在程序结束时打印一个报告
使用Noisy.h 演示vector分配的存储区溢出的情形

//: C07:VectorOverflow.cpp {-bor}
// From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison.
// (c) 1995-2004 MindView, Inc. All Rights Reserved.
// See source code use permissions stated in the file 'License.txt',
// distributed with the code package available at www.MindView.net.
// Shows the copy-construction and destruction
// that occurs when a vector must reallocate.
//{L} Noisy
#include <cstdlib>
#include <iostream>
#include <string>
#include <vector>
#include "Noisy.h"
using namespace std;

int main(int argc, char* argv[]) {
  int size = 1000;
  if(argc >= 2) size = atoi(argv[1]);
  vector<Noisy> vn;
  Noisy n;
  for(int i = 0; i < size; i++)
    vn.push_back(n);
  cout << "\n cleaning up " << endl;
  getchar();
} ///:~


输出
d[0]
c[0]
c[0]
~[0]
c[0]
c[0]
c[0]
~[0]
~[0]
c[0]
c[0]
c[0]
c[0]
~[0]
~[0]
~[0]
c[0]
c[0]
c[0]
c[0]
c[0]
~[0]
~[0]
~[0]
~[0]
c[0]
c[0]
c[0]
c[0]
c[0]
c[0]
c[0]
c[0]
~[0]
~[0]
~[0]
~[0]
~[0]
~[0]
c[0]
c[0]
c[0]
c[0]
c[0]
c[0]
c[0]
c[0]

随机出现 我用ctrl+c终止输出

运行该程序 会看到一个默认构造函数调用 为n
然后是很多的拷贝构造函数的调用
接下来看到新函数的调用
然后又是很多拷贝函数的调用
当vector用光了为线性数组分配的空间字节时
vector必须获得一块更大的存储空间并且将原来的内容全部移过去
先拷贝再销毁原来的对象

vector的内存重分配会更糟
因为vector在一个优美间接的数组中保存它的对象
被vector使用的迭代器可以是简单的指针

//: C07:VectorCoreDump.cpp
// From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison.
// (c) 1995-2004 MindView, Inc. All Rights Reserved.
// See source code use permissions stated in the file 'License.txt',
// distributed with the code package available at www.MindView.net.
// Invalidating an iterator.
#include <iterator>
#include <iostream>
#include <vector>
using namespace std;

int main() {
  vector<int> vi(10, 0);
  ostream_iterator<int> out(cout, " ");
  vector<int>::iterator i = vi.begin();
  *i = 47;
  copy(vi.begin(), vi.end(), out);
  cout << endl;
  // Force it to move memory (could also just add
  // enough objects):
  vi.resize(vi.capacity() + 1);
  // Now i points to wrong memory:
  *i = 48;  // Access violation
  copy(vi.begin(), vi.end(), out); // No change to vi[0]
  getchar();
} ///:~


输出  后跳出一个异常对话框
47 0 0 0 0 0 0 0 0 0

迭代器无效 iterator invalidation
某种操作引发设计容器底层数据的内部变化
在变化之前有效的那些迭代器可能后来不再有效

猜你喜欢

转载自blog.csdn.net/eyetired/article/details/82347385