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
252
253
254
255
256
257
258
259
260
|
/****************************************************************************
**
** Qt Shared Classes Documentation
**
** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
**
** This file is part of the Qt GUI Toolkit.
**
** This file may be used under the terms of the GNU General
** Public License versions 2.0 or 3.0 as published by the Free
** Software Foundation and appearing in the files LICENSE.GPL2
** and LICENSE.GPL3 included in the packaging of this file.
** Alternatively you may (at your option) use any later version
** of the GNU General Public License if such license has been
** publicly approved by Trolltech ASA (or its successors, if any)
** and the KDE Free Qt Foundation.
**
** Please review the following information to ensure GNU General
** Public Licensing requirements will be met:
** http://trolltech.com/products/qt/licenses/licensing/opensource/.
** If you are unsure which license is appropriate for your use, please
** review the following information:
** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
** or contact the sales department at [email protected].
**
** This file may be used under the terms of the Q Public License as
** defined by Trolltech ASA and appearing in the file LICENSE.QPL
** included in the packaging of this file. Licensees holding valid Qt
** Commercial 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 WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
** herein.
**
**********************************************************************/
/*!
\page shclass.html
\title Shared Classes
\keyword reference counting
\keyword implicit sharing
\keyword explicit sharing
\keyword implicitly shared
\keyword explicitly shared
\keyword explicit sharing
\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, 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.
Object assignment (with operator=()) for implicitly and explicitly
shared objects is implemented using shallow copies. A deep copy can be
made by calling a copy() function or by using \l QDeepCopy.
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.
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
//Line 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 to 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 that the shared data is copied to make sure that an object has
its own private data. Therefore, modifying \c a on line 7 does 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. (This is often called "copy-on-write".) Explicit sharing
leaves this job to the programmer. If an explicitly shared object is
not detached, changing an object will change all other objects that
refer to the same data.
Implicit sharing optimizes memory use 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() or
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 benefit 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
also happens if anything is \link ::bitBlt() bitBlt()\endlink'ed into
\c p2.
\warning Do not copy an implicitly shared container (QMap,
QValueVector, etc.) while you are iterating over it.
\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.
*/
|