指针版的PStash(用一个void指针数组, 来保存存入元素的地址) 附模板化实现 p321

由容器PStash的使用者,负责清除容器中的所有指针。所以用户必须记住放到容器中的是什么类型,在取出时,把取出的void指针转换成对应的类型指针,然后 'delete 转换后的对象指针',才能在清除时调到对象的析构函数。

析构函数的作用: 确保对象的各部分被正确的清除,及做一些用户指定的其他清理工作。

1 头文件PStash.h

 1 #ifndef PSTASH_H
 2 #define PSTASH_H
 3 
 4 class PStash
 5 {
 6     int capacity;
 7     int next;
 8     void** storage; //void* st[]; void** storage = st;可以看是一个'指向指针数组'首元素的指针
 9     void inflate(int increase);
10 public:
11     PStash() : capacity(0), next(0), storage(0) {}
12     ~PStash();
13 
14     int add(void* element);
15     void* operator[](int index) const;
16     void* remove(int index);
17     int count() const {    return next; }
18 };
19 #endif

2 PStash.cpp

 1 #include "PStash.h"
 2 #include "../require.h"
 3 #include <iostream>
 4 #include <cstring>
 5 
 6 
 7 using namespace std;
 8 
 9 PStash::~PStash()
10 {
11     for (int i = 0; i < next; i++)
12     {
13         //如果storage[i] == 0为false,即指针值storage[0,1,2,3,4]有不为0的,表明存在没有清除的元素
14         require(storage[i] == 0, "PStash not cleaned up");    
15     }
16     
17     // void** st = new void*[capacity + increase];
18     // storage 是void类型指针的数组,即数组storage的元素是void型指针
19     delete []storage; //清除指针数组这个容器
20     storage = 0;
21     cout << "after delete []storage;" << endl;
22 }
23 
24 
25 int PStash::add(void* element)
26 {
27     const int ssize = 10;
28     if (next >= capacity)
29         inflate(ssize);
30     cout << "storage[" << next << "] = " << element << endl;
31     storage[next++] = element;
32     return next - 1;
33 }
34 
35 
36 
37 //重载[]运算符, intPStash[i] 返回值是void类型指针
38 void* PStash::operator [](int index) const
39 {
40     require(index >= 0, "PStash::operator[] index negative");
41     if (index >= next)
42         return 0;
43 
44     return storage[index];
45 }
46 
47 
48 //把栈中index索引处的元素(指针)清零
49 void* PStash::remove(int index)
50 {
51     void* v = operator[](index);
52     if (v != 0)
53         storage[index] = 0;
54     return v;
55 }
56 
57 
58 void PStash::inflate(int increase)
59 {
60     const int psz = sizeof(void*); //地址占4个字节
61 
62     //创建了一个void*数组(void型指针的数组)
63     //该语句在堆上一口气创建capacity + increase个void指针
64     void** st = new void*[capacity + increase]; //new 一个包含 capacity + 10个void*元素的指针数组
65 
66     memset(st, 0, (capacity + increase) * psz); //该指针数组st共占(capacity + increase) * psz个字节    
67     
68     //storage是void类型指针数组,所有拷贝的是数组中元素(指针),是地址拷贝,不存在清除对象问题
69     //拷贝完后,要清除这个废弃的指针数组
70     memcpy(st, storage, capacity * psz); //把从storage地址开始的capacity * psz字节内容拷贝到st地址空间
71 
72     capacity += increase;
73     delete []storage;
74     storage = st;
75 }

3 测试文件PStashTest.cpp -- PStash使用者

 1 #include "PStash.h"
 2 #include "../require.h"
 3 #include <iostream>
 4 #include <fstream>
 5 #include <string>
 6 #include "Book.h"
 7 
 8 using namespace std;
 9 
10 int main()
11 {
12     {
13         PStash intStack;
14         for (int i = 0; i < 5; i++)
15         {
16             intStack.add(new int(i));
17         }
18         for (int k = 0; k < 5; k++ )
19         {
20             delete intStack.remove(k);
21         }
22     }
23     
24     cout << "--------------------------------" << endl;
25     
26     {
27         PStash strings;
28         
29         string* s1 = new string("hello");
30         string* s2 = new string("world");
31         
32         cout << s1 << endl;
33         cout << s2 << endl;
34         
35         strings.add(s1);
36         strings.add(s2);
37         
38         delete (string*) strings.remove(0);
39         delete (string*) strings.remove(1);
40     }
41     
42     cout << "-----------------------------------" << endl;
43     
44     {
45         Book* b1 = new Book("算法精解", "Kyle Loudon", 56.2);
46         Book* b2 = new Book("Qt程序设计", "Pulat", 10.2);
47         
48         PStash books;
49         books.add(b1);
50         books.add(b2);
51         
52         cout << "book1: " << b1 << endl;
53         cout << "book2: " << b2 << endl;
54         delete (Book*) books.remove(0);
55         delete books.remove(1); //books.remove(1)返回的是void型指针,所以此次的delete不会调用Book类的析构函数,而仅仅是释放了内容
56         //通常在析构函数中,会完成一些其他操作
57     }
58     
59     cout << "--------------- end ---------------" << endl;
60     return 0;
61 };

运行结果:

运行过程分析:

附Book类定义

Book.h

 1 #ifndef BOOK_H
 2 #define BOOK_H
 3 #include <string>
 4 
 5 using std::string;
 6 
 7 class Book
 8 {
 9 
10     string name;
11     string author;
12     double price;
13 
14 public:
15     Book();
16     Book(string name, string author, double price);
17 
18     //复制构造函数
19     Book(const Book& b);
20 
21     ~Book();
22 
23     //把重载的<<运算符全局函数声明为友元
24     friend std::ostream& operator<<(std::ostream& os, const Book& b)
25     {
26         return os << "BookName: " << b.name << ", BookAuthor: " << b.author << ", BookPrice: " << b.price;
27     }
28 
29     //重载赋值运算符
30     Book& operator=(const Book& b);
31 };
32 #endif

Book.cpp

 1 #include "Book.h"
 2 #include <iostream>
 3 
 4 using namespace std;
 5 
 6 
 7 Book::Book() : name("null"), author("null"), price(0) 
 8 {
 9     cout << "invoke constructor Book() " << endl;
10 }
11 
12 
13 Book::Book(string name, string author, double price) : name(name), author(author), price(price) 
14 {
15     cout << "invoke constructor Book(string " << name << ", string " << author << ", double "<< price << ") " << endl;
16 }
17 
18 //复制构造函数
19 Book::Book(const Book& b) : name(b.name), author(b.author), price(b.price) 
20 {
21     cout << "Book::Book(const Book& b)" << endl;
22 }
23 
24 Book::~Book()
25 {
26     cout << "~Book()" << endl;
27     cout << "free book: '" << name << "'" << endl;
28 }
29 
30 
31 //重载赋值运算符
32 Book& Book::operator=(const Book& b)
33 {
34     cout << "Book::operator=(const Book&)" << endl;
35     name = b.name;
36     author = b.author;
37     price = b.price;
38     
39     return *this;
40 }

附, 模板化实现, 当模板化容器对象超出作用域时,能够负责清理容器中剩余的指针元素指向的对象

  --- 因为模板化容器知道容器中存放元素的类型 (PStash<Book>,在目标特化时,容器中元素的类型已限定)

1)模板定义文件TPStash.h

  1 #ifndef TPSTASH_H
  2 #define TPSTASH_H
  3 
  4 #include "../require.h"
  5 
  6 template<class T, int incr = 10>
  7 class PStash
  8 {
  9     int capacity;
 10     int next;
 11     T** storage;
 12     void inflate(int increase = incr);
 13 
 14 public:
 15 
 16     PStash() : capacity(0), next(0), storage(0) {}
 17     ~PStash();
 18     
 19     int add(T* element);
 20     T* operator[](int index) const;
 21     T* remove(int index);
 22     T* pop();
 23     int count() const {    return next; }
 24 };
 25 
 26 
 27 
 28 //插入T型的指针元素element到容器,并返回插入位置索引
 29 template<class T, int incr>
 30 int PStash<T, incr>::add(T* element)
 31 {
 32     if (next >= capacity)
 33         inflate(incr);
 34 
 35     storage[next++] = element;
 36     return next - 1;
 37 }
 38 
 39 
 40 //重载运算符[]
 41 // T* ele = pstash[2]
 42 // 入参: int, 返回值类型: T*, 该容器插入和取出的都是T类型的指针
 43 template<class T, int incr>
 44 T* PStash<T, incr>::operator[](int index) const
 45 {
 46     //若index >= 0为false,则向stderr打印错误提示信息"PStash::operator[] index negative",并终止程序的执行
 47     require(index >= 0, "PStash::operator[] index negative"); 
 48 
 49     if (index >= next)
 50         return 0;
 51 
 52     require(storage[index] != 0, "PStash::operator[] returned null pointer");
 53 
 54     return storage[index];
 55 }
 56 
 57 template<class T, int incr>
 58 T* PStash<T, incr>::remove(int index)
 59 {
 60     //T* t = storage[index];
 61     //为什么使用operator[](index)来去索引index出的指针元素,因为重载后的[]运算符是安全的受检查的
 62     T* t = operator[](index);
 63     if (t != 0)
 64     {
 65         storage[index] = 0;
 66     }
 67     return t;
 68 }
 69 
 70 
 71 template<class T, int incr>
 72 T* PStash<T, incr>::pop()
 73 {
 74     int top = next - 1;
 75     T* t = operator[](top);
 76     if (t != 0)
 77     {
 78         storage[top] = 0;
 79     }
 80     next--;
 81     return t;
 82 }
 83 
 84 
 85 template<class T, int incr>
 86 void PStash<T, incr>::inflate(int increase)
 87 {
 88     const int psz = sizeof(T*);
 89 
 90     //int* a = new int[5];
 91     //在对上分配一个长度为capacity + increase的T类型的指针数组
 92     T** st = new T*[capacity + increase];
 93 
 94     memset(st, 0, (capacity + increase) * psz);
 95     memcpy(st, storage, capacity * psz);
 96 
 97     capacity += increase;
 98     delete []storage;
 99 
100     storage = st;
101 }
102 
103 
104 template<class T, int incr>
105 PStash<T, incr>::~PStash()
106 {
107     int n = 0;
108     std::cout << "------- ~PStash() ------" << std::endl;
109     //清除容器中剩余元素占用的内存空间
110     for (int i = 0; i < next; i++)
111     {
112         T* ele = storage[i];
113         std::cout << ++n << ": " << ele << ": " << *ele << std::endl;
114         delete ele;
115         storage[i] = 0;
116     }
117     
118     //清除inflate()中在堆上分配的指针数组占用的内存空间
119     delete []storage;
120 }
121 
122 #endif

 2)测试文件

 1 #include "TPStash.h"
 2 #include <iostream>
 3 #include <string>
 4 #include "Book.h"
 5 
 6 using namespace std;
 7 
 8 
 9 int main()
10 {
11     cout << endl <<  "---------- PStash<string, 5> ----------------------" << endl;
12     {
13         PStash<string, 5> strings;
14         
15         string* s1 = new string("hello");
16         string* s2 = new string("world");
17         
18         cout << s1 << endl;
19         cout << s2 << endl;
20         
21         
22         strings.add(s1);
23         strings.add(s2);
24     }
25     
26     cout << endl << "----------- PStash<Book, 5> ------------------------" << endl;
27     
28     {
29         Book* b1 = new Book("算法精解", "Kyle Loudon", 56.2);
30         Book* b2 = new Book("Qt程序设计", "Pulat", 10.2);
31         
32         PStash<Book, 5> books;
33         books.add(b1);
34         books.add(b2);
35         
36         cout << "book1: " << b1 << endl;
37         cout << "book2: " << b2 << endl;
38 
39         Book* bk3 = books.pop(); 
40         cout << "pop(): " << *bk3 << endl;
41         delete bk3; //从容器中取出来的Book指针,要负责清除该指针指向的Book对象
42     }
43 
44     cout << "------------- End --------------------------------" << endl;
45     
46     return 0;
47     
48 };

运行结果:

原文地址:https://www.cnblogs.com/asnjudy/p/4604583.html