指针版的PStash(用一个void指针数组, 来保存存入元素的地址) 附模板化实现 p321
2015-06-27 20:07
531 查看
由容器PStash的使用者,负责清除容器中的所有指针。所以用户必须记住放到容器中的是什么类型,在取出时,把取出的void指针转换成对应的类型指针,然后 'delete 转换后的对象指针',才能在清除时调到对象的析构函数。
析构函数的作用: 确保对象的各部分被正确的清除,及做一些用户指定的其他清理工作。
1 头文件PStash.h
2 PStash.cpp
3 测试文件PStashTest.cpp -- PStash使用者
运行结果:
运行过程分析:
附Book类定义
Book.h
Book.cpp
附, 模板化实现, 当模板化容器对象超出作用域时,能够负责清理容器中剩余的指针元素指向的对象
--- 因为模板化容器知道容器中存放元素的类型 (PStash<Book>,在目标特化时,容器中元素的类型已限定)
1)模板定义文件TPStash.h
2)测试文件
运行结果:
析构函数的作用: 确保对象的各部分被正确的清除,及做一些用户指定的其他清理工作。
1 头文件PStash.h
#ifndef PSTASH_H #define PSTASH_H class PStash { int capacity; int next; void** storage; //void* st[]; void** storage = st;可以看是一个'指向指针数组'首元素的指针 void inflate(int increase); public: PStash() : capacity(0), next(0), storage(0) {} ~PStash(); int add(void* element); void* operator[](int index) const; void* remove(int index); int count() const { return next; } }; #endif
2 PStash.cpp
#include "PStash.h" #include "../require.h" #include <iostream> #include <cstring> using namespace std; PStash::~PStash() { for (int i = 0; i < next; i++) { //如果storage[i] == 0为false,即指针值storage[0,1,2,3,4]有不为0的,表明存在没有清除的元素 require(storage[i] == 0, "PStash not cleaned up"); } // void** st = new void*[capacity + increase]; // storage 是void类型指针的数组,即数组storage的元素是void型指针 delete []storage; //清除指针数组这个容器 storage = 0; cout << "after delete []storage;" << endl; } int PStash::add(void* element) { const int ssize = 10; if (next >= capacity) inflate(ssize); cout << "storage[" << next << "] = " << element << endl; storage[next++] = element; return next - 1; } //重载[]运算符, intPStash[i] 返回值是void类型指针 void* PStash::operator [](int index) const { require(index >= 0, "PStash::operator[] index negative"); if (index >= next) return 0; return storage[index]; } //把栈中index索引处的元素(指针)清零 void* PStash::remove(int index) { void* v = operator[](index); if (v != 0) storage[index] = 0; return v; } void PStash::inflate(int increase) { const int psz = sizeof(void*); //地址占4个字节 //创建了一个void*数组(void型指针的数组) //该语句在堆上一口气创建capacity + increase个void指针 void** st = new void*[capacity + increase]; //new 一个包含 capacity + 10个void*元素的指针数组 memset(st, 0, (capacity + increase) * psz); //该指针数组st共占(capacity + increase) * psz个字节 //storage是void类型指针数组,所有拷贝的是数组中元素(指针),是地址拷贝,不存在清除对象问题 //拷贝完后,要清除这个废弃的指针数组 memcpy(st, storage, capacity * psz); //把从storage地址开始的capacity * psz字节内容拷贝到st地址空间 capacity += increase; delete []storage; storage = st; }
3 测试文件PStashTest.cpp -- PStash使用者
#include "PStash.h" #include "../require.h" #include <iostream> #include <fstream> #include <string> #include "Book.h" using namespace std; int main() { { PStash intStack; for (int i = 0; i < 5; i++) { intStack.add(new int(i)); } for (int k = 0; k < 5; k++ ) { delete intStack.remove(k); } } cout << "--------------------------------" << endl; { PStash strings; string* s1 = new string("hello"); string* s2 = new string("world"); cout << s1 << endl; cout << s2 << endl; strings.add(s1); strings.add(s2); delete (string*) strings.remove(0); delete (string*) strings.remove(1); } cout << "-----------------------------------" << endl; { Book* b1 = new Book("算法精解", "Kyle Loudon", 56.2); Book* b2 = new Book("Qt程序设计", "Pulat", 10.2); PStash books; books.add(b1); books.add(b2); cout << "book1: " << b1 << endl; cout << "book2: " << b2 << endl; delete (Book*) books.remove(0); delete books.remove(1); //books.remove(1)返回的是void型指针,所以此次的delete不会调用Book类的析构函数,而仅仅是释放了内容 //通常在析构函数中,会完成一些其他操作 } cout << "--------------- end ---------------" << endl; return 0; };
运行结果:
运行过程分析:
附Book类定义
Book.h
#ifndef BOOK_H #define BOOK_H #include <string> using std::string; class Book { string name; string author; double price; public: Book(); Book(string name, string author, double price); //复制构造函数 Book(const Book& b); ~Book(); //把重载的<<运算符全局函数声明为友元 friend std::ostream& operator<<(std::ostream& os, const Book& b) { return os << "BookName: " << b.name << ", BookAuthor: " << b.author << ", BookPrice: " << b.price; } //重载赋值运算符 Book& operator=(const Book& b); }; #endif
Book.cpp
#include "Book.h" #include <iostream> using namespace std; Book::Book() : name("null"), author("null"), price(0) { cout << "invoke constructor Book() " << endl; } Book::Book(string name, string author, double price) : name(name), author(author), price(price) { cout << "invoke constructor Book(string " << name << ", string " << author << ", double "<< price << ") " << endl; } //复制构造函数 Book::Book(const Book& b) : name(b.name), author(b.author), price(b.price) { cout << "Book::Book(const Book& b)" << endl; } Book::~Book() { cout << "~Book()" << endl; cout << "free book: '" << name << "'" << endl; } //重载赋值运算符 Book& Book::operator=(const Book& b) { cout << "Book::operator=(const Book&)" << endl; name = b.name; author = b.author; price = b.price; return *this; }
附, 模板化实现, 当模板化容器对象超出作用域时,能够负责清理容器中剩余的指针元素指向的对象
--- 因为模板化容器知道容器中存放元素的类型 (PStash<Book>,在目标特化时,容器中元素的类型已限定)
1)模板定义文件TPStash.h
#ifndef TPSTASH_H #define TPSTASH_H #include "../require.h" template<class T, int incr = 10> class PStash { int capacity; int next; T** storage; void inflate(int increase = incr); public: PStash() : capacity(0), next(0), storage(0) {} ~PStash(); int add(T* element); T* operator[](int index) const; T* remove(int index); T* pop(); int count() const { return next; } }; //插入T型的指针元素element到容器,并返回插入位置索引 template<class T, int incr> int PStash<T, incr>::add(T* element) { if (next >= capacity) inflate(incr); storage[next++] = element; return next - 1; } //重载运算符[] // T* ele = pstash[2] // 入参: int, 返回值类型: T*, 该容器插入和取出的都是T类型的指针 template<class T, int incr> T* PStash<T, incr>::operator[](int index) const { //若index >= 0为false,则向stderr打印错误提示信息"PStash::operator[] index negative",并终止程序的执行 require(index >= 0, "PStash::operator[] index negative"); if (index >= next) return 0; require(storage[index] != 0, "PStash::operator[] returned null pointer"); return storage[index]; } template<class T, int incr> T* PStash<T, incr>::remove(int index) { //T* t = storage[index]; //为什么使用operator[](index)来去索引index出的指针元素,因为重载后的[]运算符是安全的受检查的 T* t = operator[](index); if (t != 0) { storage[index] = 0; } return t; } template<class T, int incr> T* PStash<T, incr>::pop() { int top = next - 1; T* t = operator[](top); if (t != 0) { storage[top] = 0; } next--; return t; } template<class T, int incr> void PStash<T, incr>::inflate(int increase) { const int psz = sizeof(T*); //int* a = new int[5]; //在对上分配一个长度为capacity + increase的T类型的指针数组 T** st = new T*[capacity + increase]; memset(st, 0, (capacity + increase) * psz); memcpy(st, storage, capacity * psz); capacity += increase; delete []storage; storage = st; } template<class T, int incr> PStash<T, incr>::~PStash() { int n = 0; std::cout << "------- ~PStash() ------" << std::endl; //清除容器中剩余元素占用的内存空间 for (int i = 0; i < next; i++) { T* ele = storage[i]; std::cout << ++n << ": " << ele << ": " << *ele << std::endl; delete ele; storage[i] = 0; } //清除inflate()中在堆上分配的指针数组占用的内存空间 delete []storage; } #endif
2)测试文件
#include "TPStash.h" #include <iostream> #include <string> #include "Book.h" using namespace std; int main() { cout << endl << "---------- PStash<string, 5> ----------------------" << endl; { PStash<string, 5> strings; string* s1 = new string("hello"); string* s2 = new string("world"); cout << s1 << endl; cout << s2 << endl; strings.add(s1); strings.add(s2); } cout << endl << "----------- PStash<Book, 5> ------------------------" << endl; { Book* b1 = new Book("算法精解", "Kyle Loudon", 56.2); Book* b2 = new Book("Qt程序设计", "Pulat", 10.2); PStash<Book, 5> books; books.add(b1); books.add(b2); cout << "book1: " << b1 << endl; cout << "book2: " << b2 << endl; Book* bk3 = books.pop(); cout << "pop(): " << *bk3 << endl; delete bk3; //从容器中取出来的Book指针,要负责清除该指针指向的Book对象 } cout << "------------- End --------------------------------" << endl; return 0; };
运行结果:
相关文章推荐
- 巧用PyUnit中unittest特性解决接口测试产生脏数据问题
- win10手机预览版10149上手体验视频
- Android OpenGL ES(七)----理解纹理与纹理过滤
- ubuntu root默认密码(初始密码)
- Quartz 2D 详细解说
- Maven权威指南-电子书合集
- When it comes to intrusion analysis and forensics
- TCP/UDP常见端口参考
- R语言常用包分类
- Spring集成JMS
- java-jvm电子书合集
- HTTP状态码详解
- hdu 2079 选课时间
- 初探接口测试产生胀数据的原因与解决方案
- ASCII对照表
- KMP模式匹配理解
- thinkphp使用ajax提交后怎么做页面跳转
- JAVA8 最新电子书集合
- HTML转义字符
- 2008的共享服务器搭建