Note: You can read the original write-up at http://som-itsolutions.blogspot.in/2017/01/copy-on-write.html
As i was trying to recapitulate several important concepts of OOAD, naturally COW or Copy-On-Write got my attention for sometime. COW is a special technique used for efficient resource management in computer science. In C++ ‘98 standard, COW was used to define the std::string class. Although in C++ ‘11 standard, COW is not used to define the string class of the standard C++ library, but it is worth to have a look at the earlier implementation of the string class in GCC’s standard library. In COW, we defer creating of a new modifiable resource of a class in the case of copying if we keep the copy unchanged. We just refer to the old resource in the new copy. We write only when the copy changes that modifiable resource.
The following code is my effort to explain the COW concept in a String class. Let me explain some of the parts of this working code.
#include
#include
//This is using default constructor
//and copy constructor. Hence while copying it will
//use shallow copy.
class StringHolder{
public:
char* data;
int refCount;
virtual ~StringHolder(){
delete[] data;
}
};
class MyString{
private:
StringHolder* mStrHolder;
int length;
public:
//default constructor
MyString(){
mStrHolder = new StringHolder();
length = 0;
}
MyString(const char* inStr){
mStrHolder = new StringHolder();
unsigned l=strlen(inStr);
mStrHolder->data=new char[l+1];
memcpy(mStrHolder->data,inStr,l+1);
mStrHolder->refCount = 1;
length = l;
}
MyString(const MyString& inStr){
mStrHolder = inStr.mStrHolder;
mStrHolder->refCount++;
length = inStr.length;
}
//Reference counted assignment operator
MyString& operator=(const MyString& inStr){
//check against self assignment
if(this == &inStr)
return *this;
mStrHolder->refCount--;//the data of the lhs string
//does no longer point to the old char
//array
if(mStrHolder->refCount == 0)
delete mStrHolder;
mStrHolder = inStr.mStrHolder;//the lhs and rhs data
//both are pointing to the RHS data.
mStrHolder->refCount++;
length = inStr.length;
return *this;
}
//mutator service
MyString& operator+=(const MyString& inStr){
Detach();
const char* cStr = inStr.c_str();
int l = inStr.length;
const char* oldData = mStrHolder->data;
//deep copy
char* tmp=new char[length + l];
mStrHolder->data = tmp;
memcpy(mStrHolder->data, oldData, length);
strcat(mStrHolder->data,cStr);
mStrHolder->refCount=1;
length+= l;
return *this;
}
//Destructor. The virtual term is important
virtual ~MyString(){
mStrHolder->refCount--;
if(mStrHolder->refCount == 0)
delete mStrHolder;
}
//Call this function first for all the
//mutator services of this class
void Detach(){
if (mStrHolder->refCount == 1)
return;
StringHolder* temp = new