1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
|
/****************************************************************************
** $Id: qt/shclass.doc 3.0.3 edited Nov 27 19:11 $
**
** Qt Shared Classes Documentation
**
** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
**
** This file is part of the Qt GUI Toolkit.
**
** This file may be distributed under the terms of the Q Public License
** as defined by Trolltech AS of Norway and appearing in the file
** LICENSE.QPL included in the packaging of this file.
**
** This file may be distributed and/or modified under the terms of the
** GNU General Public License version 2 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.
**
** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
** licenses may use this file in accordance with the Qt Commercial License
** Agreement provided with the Software.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
** information about Qt Commercial License Agreements.
** See http://www.trolltech.com/qpl/ for QPL licensing information.
** See http://www.trolltech.com/gpl/ for GPL licensing information.
**
** Contact info@trolltech.com if any conditions of this licensing are
** not clear to you.
**
**********************************************************************/
/*!
\page shclass.html
\title Shared Classes
\keyword reference counting
\keyword implicit sharing
\keyword explicit sharing
\keyword implicitly shared
\keyword explicitly shared
\keyword shared implicitly
\keyword shared explicitly
Many C++ classes in Qt use \e explicit and \e implicit data sharing
to maximize resource usage and minimize copying of data.
\tableofcontents
\section1 Overview
A shared class consists of a pointer to a shared data block that
contains a reference count and the data.
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, and decremented when the object dereferences the shared data. The
shared data is deleted when the reference count becomes zero.
\keyword deep copy
\keyword shallow copy
When dealing with shared objects, there are two ways of copying an object.
We usually speak about \e deep and \e shallow copies. A deep copy implies
duplicating an object. A shallow copy is a reference copy, we only copy 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.
Object assignment (with operator=) for implicitly and explicitly
shared objects is implemented as shallow copies. A deep copy can be
made by calling a copy() function.
The benefit of sharing is that a program does not need to duplicate data
when it is not required, which results in less memory usage and less
copying of data. Objects can easily be assigned, sent as function
arguments and returned from functions.
Now comes the distinction between \e explicit and \e implicit sharing.
Explicit sharing means that the programmer must be aware of the fact that
objects share common data. Implicit sharing means that the sharing
mechanism takes place behind the scenes and the programmer does not need
to worry about it.
\section1 A QByteArray Example
QByteArray is an example of a shared class that uses explicit sharing.
Example:
\code
// a= b= c=
QByteArray a(3),b(2) // 1) {?,?,?} {?,?}
b[0] = 12; b[1] = 34; // 2) {?,?,?} {12,34}
a = b; // 3) {12,34} {12,34}
a[1] = 56; // 4) {12,56} {12,56}
QByteArray c = a; // 5) {12,56} {12,56} {12,56}
a.detach(); // 6) {12,56} {12,56} {12,56}
a[1] = 78; // 7) {12,78} {12,56} {12,56}
b = a.copy(); // 8) {12,78} {12,78} {12,56}
a[1] = 90; // 9) {12,90} {12,78} {12,56}
\endcode
The assignment \c {a = b} on line 3 throws away \c a's
original shared block (the reference count becomes zero), sets
\c a's shared block to point to \c b's shared block
and increments the reference count.
On line 4, the contents of \c a is modified. \c b is also modified,
because \c a and \c b refer the same data block. This is the difference
between explicit and implicit sharing (explained below).
The \c a object detaches from the common data on line 6. Detaching means
to copy the shared data to make sure that an object has its own private
data. Therefore, modifying \c a on line 7 will not affect \c b or \c c.
Finally, on line 8 we make a deep copy of \c a and assign it to \c b,
so that when \c a is modified on line 9, \c b remains unchanged.
\section1 Explicit vs. Implicit Sharing
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. Explicit sharing leaves this job to the
programmer. If an explicitly shared object is not detached, changing
the object will change all other objects that refer to the same data.
Implicit sharing optimizes memory usage and copying of data without this
side effect. So why didn't we implement implicit sharing for all
shared classes? The answer is that a class that allows direct access to
its internal data (for efficiency reasons), like QByteArray, cannot be
implicitly shared, because it can be changed without letting QByteArray
know.
An implicitly shared class has total control of its internal data. In any
member functions that modify its data, it automatically detaches
before modifying the data.
The QPen class, which uses implicit sharing, detaches from the shared data
in all member functions that change the internal data.
Code fragment:
\code
void QPen::setStyle( PenStyle s )
{
detach(); // detach from common data
data->style = s; // set the style member
}
void QPen::detach()
{
if ( data->count != 1 ) // only if >1 reference
*this = copy();
}
\endcode
This is clearly not possible for QByteArray, because the programmer can
do the following:
\code
QByteArray array( 10 );
array.fill( 'a' );
array[0] = 'f'; // will modify array
array.data()[1] = 'i'; // will modify array
\endcode
If we monitor changes in a QByteArray, the QByteArray class would
become unacceptably slow.
\section1 Explicitly Shared Classes
All classes that are instances of the QMemArray template class are explicitly
shared:
\list
\i \l QBitArray
\i \l QPointArray
\i \l QByteArray
\i Any other instantiation of \link QMemArray QMemArray\<type\>\endlink
\endlist
These classes have a detach() function that can be called if you want your
object to get a private copy of the shared data. They also have a copy()
function that returns a deep copy with a reference count of 1.
The same is true for \l QImage, which does not inherit QMemArray. \l QMovie
is also explicitly shared, but it does not support detach() and copy().
\section1 Implicitly Shared Classes
The Qt classes that are implicitly shared are:
\list
\i \l QBitmap
\i \l QBrush
\i \l QCursor
\i \l QFont
\i \l QFontInfo
\i \l QFontMetrics
\i \l QIconSet
\i \l QMap
\i \l QPalette
\i \l QPen
\i \l QPicture
\i \l QPixmap
\i \l QRegion
\i \l QRegExp
\i \l QString
\i \l QStringList
\i \l QValueList
\i \l QValueStack
\endlist
These classes 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 separate instances of them as separate
objects. They will always behave as separate objects but with the added
bonus of sharing data whenever possible. For this reason, you can pass
instances of these classes as arguments to functions by value without
concern for the copying overhead.
Example:
\code
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();
\endcode
In this example, \c p1 and \c p2 share data until QPainter::begin() is
called for \c p2, because painting a pixmap will modify it. The same
happens also if anything is \link ::bitBlt() bitBlt()\endlink'ed into \c p2.
\section1 QCString: implicit or explicit?
\l QCString uses a mixture of implicit and explicit sharing. Functions
inherited from QByteArray, such as data(), employ explicit sharing, while
those only in QCString detach automatically. Thus, QCString is rather an
"experts only" class, provided mainly to ease porting from Qt 1.x to Qt 2.0.
We recommend that you use \l QString, a purely implicitly shared class.
*/
|