//reference count, copy-on-write
//注意:delete this;析构函数调用以及operator<<()运算符的使用;
#include <stdio.h>
#include <iostream>
#include <../require.h>
#include <string>
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 << "Attached Dog:" << *this << endl;
}
void attach()
{
++refcount;
cout << "Attach 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;
//not 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 << endl;
}
};
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;
}