zoukankan      html  css  js  c++  java
  • 指针版的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 };

    运行结果:

  • 相关阅读:
    .NET实现Excel文件的读写 未测试
    权限管理设计
    struts1中配置应用
    POJ 2139 Six Degrees of Cowvin Bacon(floyd)
    POJ 1751 Highways
    POJ 1698 Alice's Chance
    POJ 1018 Communication System
    POJ 1050 To the Max
    POJ 1002 4873279
    POJ 3084 Panic Room
  • 原文地址:https://www.cnblogs.com/asnjudy/p/4604583.html
Copyright © 2011-2022 走看看