Skip to content

Commit 0164334

Browse files
committed
SingletonPtr: API extensions, make constexpr
* Adjust definition to make the default constructor `constexpr`. This permits use in classes that want lazy initialization and their own `constexpr` constructor, such as `mstd::mutex`. * Add `get_no_init()` method to allow an explicit optimisation for paths that know they won be the first call (such as `mstd::mutex::unlock`). * Add `destroy()` method to permit destruction of the contained object. (`SingletonPtr`'s destructor does not call its destructor - a cheat to omit destructors of static objects). Needed if using in a class that needs proper destruction.
1 parent 0800a16 commit 0164334

File tree

2 files changed

+47
-6
lines changed

2 files changed

+47
-6
lines changed

platform/SingletonPtr.h

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -86,20 +86,25 @@ inline static void singleton_unlock(void)
8686
template <class T>
8787
struct SingletonPtr {
8888

89+
// Initializers are required to make default constructor constexpr
90+
// If we were ever used as an automatic object, the explicit zero-initialization of
91+
// _data would be pointless runtime cost, but as a static object it's free.
92+
constexpr SingletonPtr() : _ptr(), _data() { }
93+
8994
/** Get a pointer to the underlying singleton
9095
*
9196
* @returns
9297
* A pointer to the singleton
9398
*/
9499
T *get() const
95100
{
96-
T *p = static_cast<T *>(core_util_atomic_load_ptr(&_ptr));
101+
T *p = core_util_atomic_load(&_ptr);
97102
if (p == NULL) {
98103
singleton_lock();
99-
p = static_cast<T *>(_ptr);
104+
p = _ptr;
100105
if (p == NULL) {
101106
p = new (_data) T();
102-
core_util_atomic_store_ptr(&_ptr, p);
107+
core_util_atomic_store(&_ptr, p);
103108
}
104109
singleton_unlock();
105110
}
@@ -129,14 +134,48 @@ struct SingletonPtr {
129134
return *get();
130135
}
131136

132-
// This is zero initialized when in global scope
133-
mutable void *_ptr;
137+
/** Get a pointer to the underlying singleton
138+
*
139+
* Gets a pointer without initialization - can be
140+
* used as an optimization when it is known that
141+
* initialization must have already occurred.
142+
*
143+
* @returns
144+
* A pointer to the singleton, or NULL if not
145+
* initialized.
146+
*/
147+
T *get_no_init() const
148+
{
149+
return _ptr;
150+
}
151+
152+
/** Destroy the underlying singleton
153+
*
154+
* The underlying singleton is never automatically destroyed;
155+
* this is a potential optimization to avoid destructors
156+
* being pulled into an embedded image on the exit path,
157+
* which should never occur. The destructor can be
158+
* manually invoked via this call.
159+
*
160+
* Unlike construction, this is not thread-safe. After this call,
161+
* no further operations on the object are permitted.
162+
*
163+
* Is a no-op if the object has not been constructed.
164+
*/
165+
void destroy()
166+
{
167+
if (_ptr) {
168+
_ptr->~T();
169+
}
170+
}
171+
172+
mutable T *_ptr;
134173
#if __cplusplus >= 201103L && !defined __CC_ARM
135174
// Align data appropriately (ARM Compiler 5 does not support alignas in C++11 mode)
136175
alignas(T) mutable char _data[sizeof(T)];
137176
#else
138177
// Force data to be 8 byte aligned
139-
mutable uint64_t _data[(sizeof(T) + sizeof(uint64_t) - 1) / sizeof(uint64_t)];
178+
mutable uint64_t _data[(sizeof(T) + sizeof(uint64_t) - 1) / sizeof(uint64_t)] = { };
140179
#endif
141180
};
142181

tools/test/travis-ci/doxy-spellchecker/ignore.en.pws

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,9 @@ retval
4646
dequeue
4747
assertation
4848
destructor
49+
destructors
4950
constructor
51+
constructors
5052
ctor
5153
dtor
5254
dereference

0 commit comments

Comments
 (0)