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
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
|
// Copyright (C) 2021 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\macro Q_GLOBAL_STATIC(Type, VariableName, ...)
\since 5.1
\relates QGlobalStatic
Creates a global and static object of type \l QGlobalStatic, of name \a
VariableName and that behaves as a pointer to \a Type. The object created
by Q_GLOBAL_STATIC initializes itself on the first use, which means that it
will not increase the application or the library's load time. Additionally,
the object is initialized in a thread-safe manner on all platforms.
Since Qt 6.3, this macro admits variadic arguments, which are used to
initialize the object, thus making the need for \l
Q_GLOBAL_STATIC_WITH_ARGS unnecessary. Please note the arguments do not
require an extra set of parentheses, unlike the older macro.
The typical use of this macro is as follows, in a global context (that is,
outside of any function bodies):
\code
Q_GLOBAL_STATIC(MyType, staticType)
\endcode
This macro is intended to replace global static objects that are not POD
(Plain Old Data, or in C++11 terms, not made of a trivial type), hence the
name. For example, the following C++ code creates a global static:
\code
static MyType staticType;
\endcode
Compared to Q_GLOBAL_STATIC, and assuming that \c MyType is a class or
struct that has a constructor, a destructor, or is otherwise non-POD, the
above has the following drawbacks:
\list
\li it requires load-time initialization of \c MyType (that is, the
default constructor for \c MyType is called when the library or
application is loaded);
\li the type will be initialized even if it is never used;
\li the order of initialization and destruction among different
translation units is not determined, leading to possible uses before
initialization or after destruction;
\endlist
The Q_GLOBAL_STATIC macro solves all of the above problems by guaranteeing
thread-safe initialization on first use and allowing the user to query for
whether the type has already been destroyed, to avoid the
use-after-destruction problem (see QGlobalStatic::isDestroyed()).
\section1 Constructor and Destructor
For Q_GLOBAL_STATIC, the type \c Type must be publicly
default-constructible and publicly destructible. For
Q_GLOBAL_STATIC_WITH_ARGS(), there must be a public constructor that
matches the arguments passed.
It is not possible to use Q_GLOBAL_STATIC with types that have protected or
private default constructors or destructors (for Q_GLOBAL_STATIC_WITH_ARGS(),
a protected or private constructor matching the arguments). If the type in
question has those members as protected, it is possible to overcome the
issue by deriving from the type and creating public a constructor and
destructor. If the type has them as private, a friend declaration is
necessary before deriving.
For example, the following is enough to create \c MyType based on a
previously-defined \c MyOtherType which has a protected default constructor
and/or a protected destructor (or has them as private, but that defines \c
MyType as a friend).
\code
class MyType : public MyOtherType { };
Q_GLOBAL_STATIC(MyType, staticType)
\endcode
No body for \c MyType is required since the destructor is an implicit
member and so is the default constructor if no other constructors are
defined. For use with Q_GLOBAL_STATIC_WITH_ARGS(), however, a suitable
constructor body is necessary:
\code
class MyType : public MyOtherType
{
public:
MyType(int i) : MyOtherType(i) {}
};
Q_GLOBAL_STATIC_WITH_ARGS(MyType, staticType, (42))
\endcode
Alternatively, if the compiler supports C++11 inheriting constructors, one could write:
\code
class MyType : public MyOtherType
{
public:
using MyOtherType::MyOtherType;
};
Q_GLOBAL_STATIC_WITH_ARGS(MyType, staticType, (42))
\endcode
\section1 Placement
The Q_GLOBAL_STATIC macro creates a type that is necessarily static, at the
global scope. It is not possible to place the Q_GLOBAL_STATIC macro inside
a function (doing so will result in compilation errors).
More importantly, this macro should be placed in source files, never in
headers. Since the resulting object is has static linkage, if the macro is
placed in a header and included by multiple source files, the object will
be defined multiple times and will not cause linking errors. Instead, each
translation unit will refer to a different object, which could lead to
subtle and hard-to-track errors.
\section1 Non-recommended uses
Note that the macro is not recommended for use with types that are POD or
that have C++11 constexpr constructors (trivially constructible and
destructible). For those types, it is still recommended to use regular
static, whether global or function-local.
This macro will work, but it will add unnecessary overhead.
\section1 Reentrancy, Thread-safety, Deadlocks, and Exception-safety on Construction
The Q_GLOBAL_STATIC macro creates an object that initializes itself on
first use in a thread-safe manner: if multiple threads attempt to
initialize the object at the same time, only one thread will proceed to
initialize, while all other threads wait for completion.
If the initialization process throws an exception, the initialization is
deemed not complete and will be attempted again when control reaches any
use of the object. If there are any threads waiting for initialization, one
of them will be woken up to attempt to initialize.
The macro makes no guarantee about reentrancy from the same thread. If the
global static object is accessed directly or indirectly from inside the
constructor, a deadlock will surely happen.
In addition, if two Q_GLOBAL_STATIC objects are being initialized on two
different threads and each one's initialization sequence accesses the
other, a deadlock might happen. For that reason, it is recommended to keep
global static constructors simple or, failing that, to ensure that there's
no cross-dependency of uses of global static during construction.
\section1 Destruction
If the object is never used during the lifetime of the program, aside from
the QGlobalStatic::exists() and QGlobalStatic::isDestroyed() functions, the
contents of type \a Type will not be created and there will not be any
exit-time operation.
If the object is created, it will be destroyed at exit-time, similar to the
C \c atexit function. On most systems, in fact, the destructor will also be
called if the library or plugin is unloaded from memory before exit.
Since the destruction is meant to happen at program exit, no thread-safety
is provided. This includes the case of plugin or library unload. In
addition, since destructors are not supposed to throw exceptions, no
exception safety is provided either.
However, reentrancy is permitted: during destruction, it is possible to
access the global static object and the pointer returned will be the same
as it was before destruction began. After the destruction has completed,
accessing the global static object is not permitted, except as noted in the
\l QGlobalStatic API.
\omit
\section1 Compatibility with Qt 4 and Qt 5.0
This macro, in its current behavior, was introduced in Qt 5.1. Prior to
that version, Qt had another macro with the same name that was private API.
This section is not meant to document how to use Q_GLOBAL_STATIC in those
versions, but instead to serve as a porting guide for Qt code that used
those macros.
The Qt 4 Q_GLOBAL_STATIC macro differed in behavior in the following ways:
\list
\li the object created was not of type \l QGlobalStatic, but instead
it was a function that returned a pointer to \a Type; that means the
\l QGlobalStatic API was not present;
\li the initialization was thread-safe, but not guaranteed to be
unique: instead, if N threads tried to initialize the object at the
same time, N objects would be created on the heap and N-1 would be
destroyed;
\li the object was always created on the heap.
\endlist
\section1 Implementation Details
Q_GLOBAL_STATIC is implemented by creating a type called \c Q_QGS_NAME
where \c NAME is the name of the variable the user passed to the macro,
inside an unnamed namespace, and a \c static variable of \l QGlobalStatic
type, named \c NAME. The use of unnamed namespaces forces the compiler to emit
non-exported symbols, often local to the translation unit, and this
propagates to the \l QGlobalStatic template instantiation that uses such
types. Additionally, because the type is used only for one variable,
there's effectively no difference between static and non-static data
members.
The "QGS" type is a \c struct containing a \c typedef to \a TYPE and a
static member function that receives a pointer to storage suitable to hold
an instance of \a TYPE. It will initialize the storage using a placement \c
new and the variadic arguments.
The majority of the work is done by the public \l QGlobalStatic class and
the private \c QtGlobalStatic::Holder class. The \c Holder union has a
single non-static member of type \a TYPE, but because this is a union, its
construction and destruction are explicitly controlled in the Holder's
constructor and destructor. The constructor calls the "QGS" type's static
member function with a pointer to this member so it can be initialized
and the destructor calls the type's destructor. The \c{Holder} type is
therefore neither trivially constructible nor trivially destructible. It is
used as a function-local \c static so its initialization is thread-safe due
to C++11's requirement that such variables be thread-safely initialized.
Additionally, both the constructor and destructor modify a guard variable
after construction and before destruction, respectively. The guard variable
is implemented as a \c {static inline} member instead of a non-static
member so the compiler and linker are free to place this variable in memory
far from the actual object. This way, if we wanted to, we could mark it
aligned-to-cacheline in the future to prevent false sharing.
The guard variable can assume the following values:
\list
\li -2: object was once initialized but has been destroyed already;
\li -1: object was initialized and is still valid;
\li 0: object was not initialized yet;
\li +1: object is being initialized and any threads encountering this
value must wait for completion (not used in the current implementation).
\endlist
Collectively, all positive values indicate that the initialization is
progressing and must be waited on, whereas all negative values indicate
that the initialization has terminated and must not be attempted again.
Positive values are not used in the current implementation, but were in
earlier versions. They could be used again in the future.
The QGlobalStatic::exists() and QGlobalStatic::isDestroyed() functions
operate solely on the guard variable: the former returns \c true if the guard
is negative, whereas the latter returns \c true only if it is -2.
\endomit
\sa Q_GLOBAL_STATIC_WITH_ARGS(), Q_APPLICATION_STATIC(), QGlobalStatic
*/
/*!
\macro Q_GLOBAL_STATIC_WITH_ARGS(Type, VariableName, Arguments)
\since 5.1
\obsolete
\relates QGlobalStatic
Creates a global and static object of type \l QGlobalStatic, of name \a
VariableName, initialized by the arguments \a Arguments and that behaves as
a pointer to \a Type. The object created by Q_GLOBAL_STATIC_WITH_ARGS
initializes itself on the first use, which means that it will not increase
the application or the library's load time. Additionally, the object is
initialized in a thread-safe manner on all platforms.
The typical use of this macro is as follows, in a global context (that is,
outside of any function bodies):
\code
Q_GLOBAL_STATIC_WITH_ARGS(MyType, staticType, (42, "Hello", "World"))
\endcode
The \a Arguments macro parameter must always include the parentheses or, if
C++11 uniform initialization is allowed, the braces. The above call is
equivalent to
\code
Q_GLOBAL_STATIC(MyType, staticType, 42, "Hello", "World")
\endcode
Aside from the actual initialization of the contents with the supplied
arguments, this macro behaves identically to Q_GLOBAL_STATIC(). Please
see that macro's documentation for more information.
\sa Q_GLOBAL_STATIC(), QGlobalStatic
*/
/*!
\class QGlobalStatic
\threadsafe
\inmodule QtCore
\since 5.1
\brief The QGlobalStatic class is used to implement a global static object.
The QGlobalStatic class is the front-end API exported when
Q_GLOBAL_STATIC() is used. See the documentation for the macro for a
discussion on when to use it and its requirements.
Normally, you will never use this class directly, but instead you will use
the Q_GLOBAL_STATIC() or Q_GLOBAL_STATIC_WITH_ARGS() macros, as
follows:
\code
Q_GLOBAL_STATIC(MyType, staticType)
\endcode
The above example creates an object of type QGlobalStatic called \c
staticType. After the above declaration, the \c staticType object may be
used as if it were a pointer, guaranteed to be initialized exactly once. In
addition to the use as a pointer, the object offers two methods to
determine the current status of the global: exists() and isDestroyed().
\sa Q_GLOBAL_STATIC(), Q_GLOBAL_STATIC_WITH_ARGS()
*/
/*!
\typedef QGlobalStatic::Type
This type is equivalent to the \c Type parameter passed to the
Q_GLOBAL_STATIC() or Q_GLOBAL_STATIC_WITH_ARGS() macros. It is used in the
return types of some functions.
*/
/*!
\fn template <typename Holder> bool QGlobalStatic<Holder>::isDestroyed() const
This function returns \c true if the global static object has already
completed destruction (that is, if the destructor for the type has already
returned). In specific, note that this function returns \c false if
the destruction is still in progress.
Once this function has returned true once, it will never return
false again until either the program is restarted or the plugin or library
containing the global static is unloaded and reloaded.
This function is safe to call at any point in the program execution: it
cannot fail and cannot cause a deadlock. Additionally, it will not cause
the contents to be created if they have not yet been created.
This function is useful in code that may be executed at program shutdown,
to determine whether the contents may still be accessed or not.
\omit
Due to the non-atomic nature of destruction, it's possible that
QGlobalStatic::isDestroyed might return false for a short time after the
destructor has finished. However, since the destructor is only run in an
environment where concurrent multithreaded access is impossible, no one can
see that state. (omitted because it's useless information)
\endomit
\sa exists()
*/
/*!
\fn template <typename Holder> bool QGlobalStatic<Holder>::exists() const
This function returns \c true if the global static object has already
completed initialization (that is, if the constructor for the type has
already returned). In specific, note that this function returns \c false if
the initialization is still in progress.
Once this function has returned true once, it will never return false again
until either the program is restarted or the plugin or library containing
the global static is unloaded and reloaded.
This function is safe to call at any point in the program execution: it
cannot fail and cannot cause a deadlock. Additionally, it will not cause
the contents to be created if they have not yet been created.
This function is useful if one can determine the initial conditions of the
global static object and would prefer to avoid a possibly expensive
construction operation.
For example, in the following code sample, this function is used to
short-circuit the creation of the global static called \c globalState and
returns a default value:
\code
Q_GLOBAL_STATIC(MyType, globalState)
QString someState()
{
if (globalState.exists())
return globalState->someState;
return QString();
}
\endcode
\b{Thread-safety notice:} this function is thread-safe in the sense that it
may be called from any thread at any time and will always return a valid
reply. But due to the non-atomic nature of construction, this function may
return false for a short time after the construction has completed.
\b{Memory ordering notice:} this function does not impose any memory
ordering guarantees. That is instead provided by the accessor functions
that return the pointer or reference to the contents. If you bypass the
accessor functions and attempt to access some global state set by the
constructor, be sure to use the correct memory ordering semantics provided
by \l QAtomicInt or \l QAtomicPointer.
\sa isDestroyed()
*/
/*!
\keyword qglobalstatic-operator-type-ptr
\fn template <typename Holder> QGlobalStatic<Holder>::operator Type*()
This function returns the address of the contents of this global static. If
the contents have not yet been created, they will be created thread-safely
by this function. If the contents have already been destroyed, this
function will return a null pointer.
This function can be used, for example, to store the pointer to the
contents of the global static in a local variable, thus avoiding multiple
calls to the function. The implementation of Q_GLOBAL_STATIC() is quite
efficient already, but in performance-critical sections it might be useful
to help the compiler a little. For example:
\code
Q_GLOBAL_STATIC(MyType, globalState)
QString someState()
{
MyType *state = globalState;
if (!state) {
// we're in a post-destruction state
return QString();
}
if (state->condition)
return state->value1;
else
return state->value2;
}
\endcode
\sa operator->(), operator*()
*/
/*!
\fn template <typename Holder> Type *QGlobalStatic<Holder>::operator()()
\deprecated
This function returns the address of the contents of this global static. If
the contents have not yet been created, they will be created thread-safely
by this function. If the contents have already been destroyed, this
function will return a null pointer.
This function is equivalent to \l {qglobalstatic-operator-type-ptr}
{operator Type *()}. It is provided for compatibility with the private
Q_GLOBAL_STATIC implementation that existed in Qt 4.x and 5.0. New code
should avoid using it and should instead treat the object as a smart
pointer.
*/
/*!
\fn template <typename Holder> Type *QGlobalStatic<Holder>::operator->()
This function returns the address of the contents of this global static. If
the contents have not yet been created, they will be created thread-safely
by this function.
This function does not check if the contents have already been destroyed and
will never return null. If this function is called after the object has
been destroyed, it will return a dangling pointer that should not be
dereferenced.
*/
/*!
\fn template <typename Holder> Type &QGlobalStatic<Holder>::operator*()
This function returns a reference to the contents of this global static. If
the contents have not yet been created, they will be created thread-safely
by this function.
This function does not check if the contents have already been destroyed.
If this function is called after the object has been destroyed, it will
return an invalid reference that must not be used.
*/
|