include #include #include #include #include // Standard C++ Library container #include //#include //1171 44 D:\hpm281\book1.cpp [Error] ‘memset’ was not declared in this scope //#include “…/require.h” inline void require(bool requirement, const std::string& msg = “Requirement failed”){ using namespace std; if (!requirement) { fputs(msg.c_str(), stderr); fputs("\n", stderr); exit(1); } }
inline void requireArgs(int argc, int args, const std::string& msg = “Must use %d arguments”) { using namespace std; if (argc != args + 1) { fprintf(stderr, msg.c_str(), args); fputs("\n", stderr); exit(1); } }
inline void requireMinArgs(int argc, int minArgs, const std::string& msg = “Must use at least %d arguments”) { using namespace std; if(argc < minArgs + 1) { fprintf(stderr, msg.c_str(), minArgs); fputs("\n", stderr); exit(1); } }
inline void assure(std::ifstream& in, const std::string& filename = “”) { using namespace std; if(!in) { fprintf(stderr, “Could not open file %s\n”, filename.c_str()); exit(1); } }
inline void assure(std::ofstream& out, const std::string& filename = “”) { using namespace std; if(!out) { fprintf(stderr, “Could not open file %s\n”, filename.c_str()); exit(1); } }
template<class T, int size = 100> class Array {//Array是被检查的对象数组,并且防止下标越界。 T array[size]; public: T& operator[](int index) { require(index >= 0 && index < size, “Index out of range”); return array[index]; } int length() const { return size; } };
class Number { float f; public: Number(float ff = 0.0f) : f(ff) {} Number& operator=(const Number& n) { f = n.f; return *this; } operator float() const { return f; } friend std::ostream& operator<<(std::ostream& os, const Number& x) { return os << x.f; } };
template<class T, int size = 20> class Holder { //类Holder很像Array,只是它有一个指向Array的指针,而不是指向类型Array的嵌入对象。 //该指针在构造函数中不被初始化,而是推迟到第一次访问时这称为懒惰初始化。 //如果创造大量的对象,但不访问每一个对象,为了节省存储,可以用懒惰初始化技术 Array<T, size>* np; public: Holder() : np(0) {} T& operator[](int i) { require(0 <= i && i < size); if(!np) np = new Array<T, size>; return np->operator; } int length() const { return size; } ~Holder() { delete np; } };
// TSTACK_H
template class Stack { struct Link { T* data; Link* next; Link(T* dat, Link* nxt): data(dat), next(nxt) {} }* head; public: Stack() : head(0) {} ~Stack(){ while(head) delete pop(); } void push(T* dat) { head = new Link(dat, head); } T* peek() const { return head ? head->data : 0; } T* pop(){ if(head == 0) return 0; T* result = head->data; Link* oldHead = head; head = head->next; delete oldHead; return result; } };
class X { public: virtual ~X() { std::cout << "~X " << std::endl; } };
// TPSTASH_H
template<class T, int incr = 10> class PStash { int quantity; // Number of storage spaces int next; // Next empty space T** storage; void inflate(int increase = incr); public: PStash() : quantity(0), next(0), storage(0) {} ~PStash(); int add(T* element); T* operator[](int index) const; // Fetch // Remove the reference from this PStash: T* remove(int index); // Number of elements in Stash: int count() const { return next; } };
template<class T, int incr> int PStash<T, incr>::add(T* element) { if(next >= quantity) inflate(incr); storage[next++] = element; return(next - 1); // Index number }
// Ownership of remaining pointers: template<class T, int incr> PStash<T, incr>::~PStash() { for(int i = 0; i < next; i++) { delete storage[i]; // Null pointers OK storage[i] = 0; // Just to be safe } delete []storage; }
template<class T, int incr> T* PStash<T, incr>::operator[](int index) const { require(index >= 0, “PStash::operator[] index negative”); if(index >= next) return 0; // To indicate the end require(storage[index] != 0, “PStash::operator[] returned null pointer”); // Produce pointer to desired element: return storage[index]; }
template<class T, int incr> T* PStash<T, incr>::remove(int index) { // operator[] performs validity checks: T* v = operator; // “Remove” the pointer: if(v != 0) storage[index] = 0; return v; }
template<class T, int incr> void PStash<T, incr>::inflate(int increase) { const int psz = sizeof(T*); T** st = new T*[quantity + increase]; memset(st, 0, (quantity + increase) * psz); memcpy(st, storage, quantity * psz); quantity += increase; delete []storage; // Old storage storage = st; // Point to new memory }
// AUTOCOUNTER_H
class AutoCounter { static int count; int id; class CleanupCheck { std::set<AutoCounter*> trace; public: void add(AutoCounter* ap) { trace.insert(ap); } void remove(AutoCounter* ap) { require(trace.erase(ap) == 1, “Attempt to delete AutoCounter twice”); } ~CleanupCheck() { std::cout << “~CleanupCheck()”<< std::endl; require(trace.size() == 0, “All AutoCounter objects not cleaned up”); } }; static CleanupCheck verifier; AutoCounter() : id(count++) { verifier.add(this); // Register itself std::cout << “created[” << id << “]” << std::endl; } // Prevent assignment and copy-construction: AutoCounter(const AutoCounter&); void operator=(const AutoCounter&); public: // You can only create objects with this: static AutoCounter* create() { return new AutoCounter(); } ~AutoCounter() { std::cout << “destroying[” << id << “]” << std::endl; verifier.remove(this); } // Print both objects and pointers: friend std::ostream& operator<<( std::ostream& os, const AutoCounter& ac){ return os << "AutoCounter " << ac.id; } friend std::ostream& operator<<( std::ostream& os, const AutoCounter* ac){ return os << "AutoCounter " << ac->id; } }; AutoCounter::CleanupCheck AutoCounter::verifier; int AutoCounter::count = 0; //Thinking in C++ p 414 int main() { Holder h; for(int i = 0; i < 20; i++) h[i] = i; for(int j = 0; j < 20; j++) std::cout << h[j] << ’ ’ ; std::cout << std::endl;
PStash<AutoCounter> acStash; for(int i = 0; i < 10; i++) acStash.add(AutoCounter::create()); std::cout << "Removing 5 manually:" << std::endl; for(int j = 0; j < 5; j++) delete acStash.remove(j); std::cout << "Remove two without deleting them:" << std::endl; // ... to generate the cleanup error message. std::cout << acStash.remove(5) << std::endl; std::cout << acStash.remove(6) << std::endl; std::cout << "The destructor cleans up the rest:" << std::endl;// 当从PStash中移出AutoCounter元素5和元素6时,它们就变成了调用者的责任, //但是因为调用者没有清除它们,所以就引起了内存泄漏,随后在运行时被AutoCounter检测到 // Repeat the test from earlier chapters:? std::ifstream in(“TPStashTest.cpp”); assure(in, “TPStashTest.cpp”); PStashstd::string stringStash; std::string line; while(getline(in, line)) stringStash.add(new std::string(line)); // Print out the strings: for(int u = 0; stringStash[u]; u++) std::cout << “stringStash[” << u << "] = " << *stringStash[u] << std::endl;
getchar();} ///:~
///Thinking in C++ p 410 int main(int argc, char argv[]) { requireArgs(argc, 1); // File name is argument std::ifstream in(argv[1]); assure(in, argv[1]); Stackstd::string textlines; std::string line; // Read file and store lines in the Stack: while(getline(in, line)) textlines.push(new std::string(line)); // Pop some lines from the stack: std::string* s; for(int i = 0; i < 10; i++) { if((s = (std::string*)textlines.pop())==0) break; std::cout << *s << std::endl; delete s; } // The destructor deletes the other strings. // Show that correct destruction happens: Stack xx; //X的析构函数是虚的,这里不是因为需要如此,而是因为xx稍后能用来存放,从X派生的对象 for(int j = 0; j < 10; j++) xx.push(new X); getchar(); } ///:~ */
/* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Must use 1 arguments
wannian07@wannian07-PC:~$ g++ -std=c++17 -o c13 c13.cpp -pthread wannian07@wannian07-PC:~$ ./c13 created[0] created[1] created[2] created[3] created[4] created[5] created[6] created[7] created[8] created[9] Removing 5 manually: destroying[0] destroying[1] destroying[2] destroying[3] destroying[4] Remove two without deleting them: AutoCounter 5 AutoCounter 6 The destructor cleans up the rest: Could not open file TPStashTest.cpp ~CleanupCheck() All AutoCounter objects not cleaned up */
