Bruce Eckel's Thinking in C++, 2nd Ed | Contents | Prev | Next |
//: C16:Getmem.h // Function template for memory #ifndef GETMEM_H #define GETMEM_H #include <cstdlib> #include <cstring> #include "../require.h" template<class T> void getmem(T*& oldmem, int elems) { typedef int cntr; // Type of element counter const int csz = sizeof(cntr); // And size const int tsz = sizeof(T); if(elems == 0) { free(&(((cntr*)oldmem)[-1])); return; } T* p = oldmem; cntr oldcount = 0; if(p) { // Previously allocated memory // Old style: // ((cntr*)p)--; // Back up by one cntr // New style: cntr* tmp = reinterpret_cast<cntr*>(p); p = reinterpret_cast<T*>(--tmp); oldcount = *(cntr*)p; // Previous # elems } T* m = (T*)realloc(p, elems * tsz + csz); require(m != 0); *((cntr*)m) = elems; // Keep track of count const cntr increment = elems - oldcount; if(increment > 0) { // Starting address of data: long startadr = (long)&(m[oldcount]); startadr += csz; // Zero the additional new memory: memset((void*)startadr, 0, increment * tsz); } // Return the address beyond the count: oldmem = (T*)&(((cntr*)m)[1]); } template<class T> inline void freemem(T * m) { getmem(m, 0); } #endif // GETMEM_H ///:~
//: C16:Getmem.cpp // Test memory function template #include <iostream> #include "Getmem.h" using namespace std; int main() { int* p = 0; getmem(p, 10); for(int i = 0; i < 10; i++) { cout << p[i] << ' '; p[i] = i; } cout << '\n'; getmem(p, 20); for(int j = 0; j < 20; j++) { cout << p[j] << ' '; p[j] = j; } cout << '\n'; getmem(p, 25); for(int k = 0; k < 25; k++) cout << p[k] << ' '; freemem(p); cout << '\n'; float* f = 0; getmem(f, 3); for(int u = 0; u < 3; u++) { cout << f[u] << ' '; f[u] = u + 3.14159; } cout << '\n'; getmem(f, 6); for(int v = 0; v < 6; v++) cout << f[v] << ' '; freemem(f); } ///:~
//: C16:Applist.cpp // Apply a function to a TStack #include <iostream> #include "TStack.h" using namespace std; // 0 arguments, any type of return value: template<class T, class R> void applist(TStack<T>& tl, R(T::*f)()) { TStackIterator<T> it(tl); while(it) { (it.current()->*f)(); it++; } } // 1 argument, any type of return value: template<class T, class R, class A> void applist(TStack<T>& tl, R(T::*f)(A), A a) { TStackIterator<T> it(tl); while(it) { (it.current()->*f)(a); it++; } } // 2 arguments, any type of return value: template<class T, class R, class A1, class A2> void applist(TStack<T>& tl, R(T::*f)(A1, A2), A1 a1, A2 a2) { TStackIterator<T> it(tl); while(it) { (it.current()->*f)(a1, a2); it++; } } // Etc., to handle maximum probable arguments class Gromit { // The techno-dog int arf; public: Gromit(int arf = 1) : arf(arf + 1) {} void speak(int) { for(int i = 0; i < arf; i++) cout << "arf! "; cout << endl; } char eat(float) { cout << "chomp!" << endl; return 'z'; } int sleep(char, double) { cout << "zzz..." << endl; return 0; } void sit(void) {} }; int main() { TStack<Gromit> dogs; for(int i = 0; i < 5; i++) dogs.push(new Gromit(i)); applist(dogs, &Gromit::speak, 1); applist(dogs, &Gromit::eat, 2.0f); applist(dogs, &Gromit::sleep, 'z', 3.0); applist(dogs, &Gromit::sit); } ///:~