• 指针版的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 };

    运行结果:

  • 相关阅读:
    d2admin框架学习
    手机访问本地配置域名下的项目
    laydate 限制结束日期不能大于起始日期
    学习MVC之租房网站(十一)-定时任务和云存储
    学习MVC之租房网站(十)-预约和跟单
    学习MVC之租房网站(九)-房源显示和搜索
    学习MVC之租房网站(八)- 前台注册和登录
    学习MVC之租房网站(七)-房源管理和配图上传
    《程序员修炼之道》笔记(九)
    《程序员修炼之道》笔记(八)
  • 原文地址:https://www.cnblogs.com/asnjudy/p/4604583.html
Copyright © 2020-2023  润新知