Skip to content

Instantly share code, notes, and snippets.

@rickyzhang-cn
Created May 15, 2015 07:34
Show Gist options
  • Select an option

  • Save rickyzhang-cn/38f1864d18bc7243d6bd to your computer and use it in GitHub Desktop.

Select an option

Save rickyzhang-cn/38f1864d18bc7243d6bd to your computer and use it in GitHub Desktop.

Revisions

  1. rickyzhang-cn created this gist May 15, 2015.
    146 changes: 146 additions & 0 deletions ReferenceCounting.cpp
    Original 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;
    } ///:~