Qt Implicit Sharing
Reference Links
- Qt - Implicit Sharing
- Qt - Implicit Sharing iterator problem
- Qt - Threads and Implicitly Shared Classes
- Qt - QSharedData
- Qt - QSharedDataPointer
Implicit Sharing
- Many C++ classes in Qt use implicit data sharing to
- maximize resource usage and
- minimize copying.
- Implicitly shared classes are both safe and efficient when passed as arguments,
- because only a pointer to the data is passed around, and
- the data is copied only if and when a function writes to it,
- i.e., copy-on-write
Overview
- A shared class consists of
- a pointer to a shared data block that contains
- a reference count and the data.
- a pointer to a shared data block that contains
- When a shared object is created, it sets the reference count to 1.
- The reference count is
- incremented whenever a new object references the shared data,
- decremented when the object dereferences the shared data.
- The shared data is deleted when the reference count becomes zero.
- The reference count is
- When dealing with shared objects, there are two ways of copying an object.
- We usually speak about deep and shallow copies.
- A deep copy implies duplicating and an object.
- A shallow copy is a reference copy,
- i.e. just a pointer to a shared data block.
- Making a deep copy can be expensive in terms of memory and CPU.
- Making a shallow copy is very fast, because it only involves setting a pointer and incrementing the reference count.
- We usually speak about deep and shallow copies.
- Object assignment (with operator=()) for implicitly shared objects is implemented using shallow copies.
- The benefit of sharing is that a program does not need to duplicate data unnecessarily,
- which results in lower memory use and less copying of data.
- Objects can easily be assigned,
- sent as function arguments, and
- returned from functions.
- Objects can easily be assigned,
- which results in lower memory use and less copying of data.
- Implicit sharing mostly takes place behind the scenes; the programmer rarely needs to worry about it.
- However, Qt’s container iterators have different behaviour than those from the STL. Read Qt - Implicit Sharing iterator problem.
- In multithreaded applications implicit sharing takes place, as explained in Qt - Threads and Implicitly Shared Classes.
- When implementing your own implicitly shared classes, use the QSharedData, and QSharedDataPointer classes.
Implicit Sharing in Detail
- Copy-On-Write or Value semantics
- Implicit sharing automatically detaches the object from a shared block
- if the object is about to change and the reference count is greater than one.
- An implicitly shared class has control of its internal data.
- In any member functions that modify its data,
- it automatically detaches before modifying the data.
- In any member functions that modify its data,
- Qt - Implicit Sharing iterator problem is the special case.
- Implicit sharing automatically detaches the object from a shared block
- The QPen class, which uses implicit sharing, detaches from the shared data in all member functions that change the internal data.
void QPen::setStyle(Qt::PenStyle style)
{
detach(); // detach from common data
d-style = style; // set the style member
}
void QPen::detach()
{
if (d->ref != 1) {
... // perform a deep copy
}
}
List of Classes
- The classes listed below automatically detach from common data if an object is about to be changed.
- The programmer will not even notice that the objects are shared.
- Thus you should treat separated instances of them as separate objects.
- They will always behave as separate objects
- but with the added benefit of sharing data whenever possible.
- They will always behave as separate objects
- For this reason, you can pass instances of these classes as arguments to functions by value without concern for the copying overhead.
QPixmap p1, p2;
p1.load("image.bmp");
p2 = p1; // p1 and p2 share data
QPainter paint;
paint.begin(&p2); // cuts p2 loose from p1
paint.drawText(0, 50, "Hi");
paint.end();
- In this example, p1 and p2 share data until QPainter::begin() is called for p2. because painting a pixmap will modify it.
Warning: Be careful with copying an implicitly shared container(QMap, QList, etc.) while you use STL-style iterator. See Implicit sharing iterator problem.