Created
May 15, 2015 07:34
-
-
Save rickyzhang-cn/38f1864d18bc7243d6bd to your computer and use it in GitHub Desktop.
Revisions
-
rickyzhang-cn created this gist
May 15, 2015 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,146 @@ //: C12:ReferenceCounting.cpp // From Thinking in C++, 2nd Edition // Available at http://www.BruceEckel.com // (c) Bruce Eckel 2000 // Copyright notice in Copyright.txt // Reference count, copy-on-write #include "../require.h" #include <string> #include <iostream> using namespace std; class Dog { string nm; int refcount; Dog(const string& name) : nm(name), refcount(1) { cout << "Creating Dog: " << *this << endl; } // Prevent assignment: Dog& operator=(const Dog& rv); public: // Dogs can only be created on the heap: static Dog* make(const string& name) { return new Dog(name); } Dog(const Dog& d) : nm(d.nm + " copy"), refcount(1) { cout << "Dog copy-constructor: " << *this << endl; } ~Dog() { cout << "Deleting Dog: " << *this << endl; } void attach() { ++refcount; cout << "Attached Dog: " << *this << endl; } void detach() { require(refcount != 0); cout << "Detaching Dog: " << *this << endl; // Destroy object if no one is using it: if(--refcount == 0) delete this; } // Conditionally copy this Dog. // Call before modifying the Dog, assign // resulting pointer to your Dog*. Dog* unalias() { cout << "Unaliasing Dog: " << *this << endl; // Don't duplicate if not aliased: if(refcount == 1) return this; --refcount; // Use copy-constructor to duplicate: return new Dog(*this); } void rename(const string& newName) { nm = newName; cout << "Dog renamed to: " << *this << endl; } friend ostream& operator<<(ostream& os, const Dog& d) { return os << "[" << d.nm << "], rc = " << d.refcount; } }; class DogHouse { Dog* p; string houseName; public: DogHouse(Dog* dog, const string& house) : p(dog), houseName(house) { cout << "Created DogHouse: "<< *this << endl; } DogHouse(const DogHouse& dh) : p(dh.p), houseName("copy-constructed " + dh.houseName) { p->attach(); cout << "DogHouse copy-constructor: " << *this << endl; } DogHouse& operator=(const DogHouse& dh) { // Check for self-assignment: if(&dh != this) { houseName = dh.houseName + " assigned"; // Clean up what you're using first: p->detach(); p = dh.p; // Like copy-constructor p->attach(); } cout << "DogHouse operator= : " << *this << endl; return *this; } // Decrement refcount, conditionally destroy ~DogHouse() { cout << "DogHouse destructor: " << *this << endl; p->detach(); } void renameHouse(const string& newName) { houseName = newName; } void unalias() { p = p->unalias(); } // Copy-on-write. Anytime you modify the // contents of the pointer you must // first unalias it: void renameDog(const string& newName) { unalias(); p->rename(newName); } // ... or when you allow someone else access: Dog* getDog() { unalias(); return p; } friend ostream& operator<<(ostream& os, const DogHouse& dh) { return os << "[" << dh.houseName << "] contains " << *dh.p; } }; int main() { DogHouse fidos(Dog::make("Fido"), "FidoHouse"), spots(Dog::make("Spot"), "SpotHouse"); cout << "Entering copy-construction" << endl; DogHouse bobs(fidos); cout << "After copy-constructing bobs" << endl; cout << "fidos:" << fidos << endl; cout << "spots:" << spots << endl; cout << "bobs:" << bobs << endl; cout << "Entering spots = fidos" << endl; spots = fidos; cout << "After spots = fidos" << endl; cout << "spots:" << spots << endl; cout << "Entering self-assignment" << endl; bobs = bobs; cout << "After self-assignment" << endl; cout << "bobs:" << bobs << endl; // Comment out the following lines: cout << "Entering rename(\"Bob\")" << endl; bobs.getDog()->rename("Bob"); cout << "After rename(\"Bob\")" << endl; } ///:~