I have been working with Qt for the past 6 months and I am still struggling to understand the concept of Implicitly shared classes. I have the following questions:
Thanx guys for all the answers..i came around another point regarding this topic is stack objects point to heap allocated shared data..this is the diagram...
any takes on this ???...and what exactly is a reference count??is it kind of a counter the incereses when objects refer to common shared data..and vice versa?
Imagine the follow. You are using C++03 and you write:
string a("hello");
string b = a;
At this moment you have two strings objects a
and b
and each one has its own buffer to store an array of chars. Even though the content of the buffers are exactly the same, a
and b
still have their own copy of "hello". This is a waste of memory. If they shared the buffer, your would have to use a single char array to store "hello world" for both strings.
Now with QString it is a bit different:
QString a("Hello");
QString b = a;
In this case , only a
created a char array to store "hello". b
instead of creating its own char array, will simply point to a
's char array. That way you save memory.
Now if you do b[0]='M'
, id est, you modify b
, then b
creates its own char array, copying the contents of a
's array and then modifying its own array.
In Java, strings are immutable objects. In other words, Java does not provide any methods on the String
class to modify its content. This is made so it is always possible to share that kind of data.
Complementing with things mentioned by others:
How can I know that I can free the char array?
That is what "reference-count" is for. When a object is created and set to point to the char array, its reference count will be incremented by 1, so it knows how many objects are still using it. When an object that pointed to it is destroyed, the reference count is decremented. When the counter reaches zero, the char array knows that no one is using it , so it can be freed.
This is a very rough implementation of reference counting. I do not intend anyway to be accurate or correct. I am ignoring the correct ways of implementing copy constructor and assignment operators in C++. I am no way checking if the implementation works. Think it is an algorithm description in somewhat like C++. I just want to teach the concept. But imagine you have these classes:
class SharedData{
private:
int refcount;
int data;
public:
SharedData(int _data){data=_data;refcount=1;}
void incRef(){refcount++;}
void decRef(){--refcount; if(refCount==0) delete this;}
};
class Data{
SharedData* shared;
public:
Data(int i){shared = new Data(i);}
Data(const Data& data){shared = data.shared; shared->incRef();}
const Data& operator=(const Data& data){if(shared!=data.shared){
shared->decRef();
shared = data.shared;
shared->incRef();}
}
~Data(){shared->decRef();}
};
Two objects of class Data
can share the same SharedData
object, so :
void someFunction() {
Data a(3) //Creates a SharedData instance and set refcount to 1
if (expression) {
Data b = a; //b points to the same SharedData than a. refcount is 2
b = Data(4);// b points to diferent SharedData. refcount of SharedData of a is decremented to 1 and b's SharedData has refcount 1
//destructor of b is called. Because shared data of b has now refcount == 0, the sharedData is freed;
}
//destructor of a is called, refcount is decremented again
// because it is zero SharedData is freed
}
So resource usage was maximized and copy was minimized. Both a
and b
used the same SharedData
(aka int 3
). . The 4
was not copied from a
to b
, they just shared the same data. An int is not big deal, but imagine if SharedData
held some big string or any other more complex data structure. Copying just a pointer is far faster than tens of bytes. And it also saves a lot of memory when you do not really need a copy.
What is copy-on-write?
Recall above what I said when we did b[0]='M'
. That was copy-on-write. b
and a
were sharing the same char array. But b
needed to modify the string. It couldn't do it directly, because that would modify the string for a
too. So b
has to create its own copy of the char array in order to be able to change it. Because it only has to create the copy when it will modify the array, it is called copy-on-write.
Based on my reading of http://doc.qt.io/archives/qt-4.7/implicit-sharing.html...
It's basically just a generic name for any class that uses reference-counting and copy-on-write to avoid unnecessary copying of the data managed by a class.
Reference-counting is a technique to ensure that an object hangs around for as long as anyone has an interest in it. Any piece of code that wants to hold onto the object for a period of time increments the reference count. When it loses interest in the object, it decrements the reference and, if the reference count hits zero, meaning that it was the last interested party, it also destroys the object.
In the case of Qt's shared classes, it appears that the reference-counting is completely automatic. Reference-counts are managed via the constructors and destructors of the classes in question.
In addition to sharing via reference-counting, classes can ensure that different parties don't clobber each other's versions of an object by making a copy of the underlying data just before doing any modifications to it. This is called the copy-on-write, or COW, idiom.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With