I want to create a copu-on-write mechanism.
I am supposed to have a class (StringHolder), that will keep a pointer to a string. I want if there are other objects with pointers to the same string the program to be aware of it and make the new pointers to point to the same string.
Plus I want it to delete the string if no pointer points to that string, should not allow to alter the string if there are other pointers to that string (instead to point in a new string), and i want to make use of the operator '+=' . A reference of more or less what i want to do is here : http://ccfit.nsu.ru/~ddol/2006-2007/oop-2-course/cow/index.html
The objects of the class StringHolder are supposed to be called in the main like this :
StringHolder a;
a("kiri");
class mystring
{
private:
strholder* ptr;
void detach();
public:
mystring()
: ptr(new strholder)
{ ptr->instancecount = 1; }
mystring(const string& setstr)
: ptr(new strholder)
{ ptr->str = setstr; ptr->instancecount = 1;}
mystring(const mystring& other) // link up this instance to data from other instance
: ptr(other.ptr)
{ ++ptr->instanceount; }
~mystring();
mystring& operator=(const mystring&);
// non mutative service
char charAt(int i) const;
// mutative service - must detach
mystring& operator+=(const mystring&);
};
mystring::~mystring()
{
--ptr->instancecount;
if(ptr->instancecount == 0) // only delete the data if no more instances
delete ptr;
}
mystring& operator=(const mystring& other)
{
if(this == &other || ptr == other.ptr) // self assignment might cause a problem
return *this;
--ptr->instancecount; // this element will no longer point to its current data
if(ptr->instancecount == 0) // and if no other instance then delete the data
delete ptr;
ptr = other.ptr; // link up to RHS object's data
++ptr->instancecount; // which now has an extra instance
return *this;
}
// do this first thing for any mutative (non const) service
void mystring::detach()
{ // make a deep copy of the object - if necessary
if(ptr->instancecount == 1) // not necessary - only one instance
return;
// make deep copy
strholder* temp new strholder;
temp->str = ptr->str; // copy string
temp->instancecount = 1;
--ptr->instancecount; // no of instances to old data is decremented
ptr = temp; // now pointing to new data with one instance
}
char mystring::charAt(int i) const
{ // this is a const service so just operate on ptr->str directly
}
mystring& mystring::operator=(const mystring& other)
{ // this is a non const service so must detach first
detach();
// now have a single instance, free to operate on the data
}
Hmm..it seems that your way is better..
But what is wrong with the way i do it?
After my first result "String kiri has : 1 pointer(s)."
I get an Segmentation fault.
I updated the code a little :
What's wrong with the way you do it? Let me count the ways.
To begin with a copy-on-write implementation of a string class should not visible outside of the class. A user of the string shouldn't care how the string's internals are implemented (and thus, should not be required to instantiate or supply a "U_ptr" in order to use the string class.)
U_ptr, what kind of name is that? Looks like it should be some kind of pointer. Is it? No, it's not.
Have you looked at the warnings generated by your compiler?
main.cpp(57): warning C4715: 'U_Ptr::AddString' : not all control paths return a value
In fact if we look at that function we can see that the only time a value is returned is when pointer_count is empty. Given that, what value do you think gets assigned to m_Data in the following code when a_ptr's map is non-empty?
1 2 3 4 5 6 7
StringHolder(std::string* a_Data, U_Ptr& a_ptr)
{
// ptr = new U_Ptr(a_Data);//creates a pointer to a U_Ptr object
m_Data = a_Data;
m_ptr = &a_ptr;
m_Data = (*m_ptr).AddString(m_Data);
}
Yes you are right..I don't know how i missed that.I fixed it and i don't get the Segmentation fault anymore.
But how should i use the class U_Ptr?I used it this way because the U_ptr object as a StringHolder constructor parameter because i couldn't think of another way.
Can you help me a little bit with that?
Thank you so much.
If you insist on the use of a map this way (which I wouldn't recommend,) you could make a U_ptr a static member of the string class, and every string object could register with the static member on construction.