-
Notifications
You must be signed in to change notification settings - Fork 320
/
Copy pathbslma_newdeleteallocator.h
388 lines (361 loc) · 16.9 KB
/
bslma_newdeleteallocator.h
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
// bslma_newdeleteallocator.h -*-C++-*-
#ifndef INCLUDED_BSLMA_NEWDELETEALLOCATOR
#define INCLUDED_BSLMA_NEWDELETEALLOCATOR
#include <bsls_ident.h>
BSLS_IDENT("$Id: $")
//@PURPOSE: Provide singleton new/delete adaptor to 'bslma::Allocator' protocol.
//
//@CLASSES:
// bslma::NewDeleteAllocator: support new/delete-style allocation/deallocation
//
//@SEE_ALSO: bslma_default, bslma_testallocator
//
//@DESCRIPTION: This component provides a concrete allocation mechanism,
// 'bslma::NewDeleteAllocator', that implements the 'bslma::Allocator' protocol
// to provide direct access to the system-supplied (native) global
// 'operator new' and 'operator delete' functions via that pure abstract
// interface.
//..
// ,-------------------------.
// ( bslma::NewDeleteAllocator )
// `-------------------------'
// | allocator
// | singleton
// | ctor/dtor
// V
// ,----------------.
// ( bslma::Allocator )
// `----------------'
// allocate
// deallocate
//..
// The essential purpose of this component is to facilitate the default use of
// global 'new' and 'delete' in all components that accept a user-supplied
// allocator derived from 'bslma::Allocator' (see 'bslma_default'). Hence, the
// global 'operator new' and 'operator delete' functions are wrapped within
// concrete methods of a derived 'bslma::NewDeleteAllocator' class. A 'static'
// (factory) method of 'bslma::NewDeleteAllocator' can be used to obtain a
// unique (singleton) 'bslma::NewDeleteAllocator' object for the given process,
// and whose lifetime is guaranteed to exceed any possibility of its use. Note
// that the standard also requires the global 'operator new' to return
// maximally-aligned memory, which is a stricter post condition than the
// natural-alignment requirement imposed by the base-class contract, or than is
// provided by many other concrete implementations.
//
///Thread Safety
///-------------
// This class is fully thread-safe, which means that all non-creator object
// methods can be safely accessed concurrently (from multiple treads). The
// singleton 'bslma::NewDeleteAllocator' can also be safely created/accessed
// concurrently (from multiple threads) via either the 'static' 'singleton' or
// 'allocator' (factory) methods. Moreover, the underlying (native)
// implementation of 'new' and 'delete' are required by the C++ standard to
// ensure that concurrent access to either the virtual 'allocate' and/or
// 'deallocate' are also safe (i.e., will not not result in heap corruption).
// Note that this allocator therefore has stronger thread-safety guarantees
// than is required by the base-class contract or than is provided by many
// other derived concrete allocators.
//
///Usage
///-----
// The most common and proper use of 'bslma::NewDeleteAllocator' is both
// *indirect* and *by* *default* (see 'bslma_default'). For example, consider
// (along with its destructor) the default and copy constructors for, say, a
// simple container, such as 'my_ShortArray', each of which take as its final
// optional argument the address of a 'bslma::Allocator' protocol:
//..
// // my_shortarray.h:
// // ...
// namespace bslma { class Allocator; }
//
// class my_ShortArray {
// short *d_array_p; // dynamically-allocated array
// int d_capacity; // physical capacity (in elements)
// int d_length; // logical length (in elements)
// bslma::Allocator *d_allocator_p; // memory allocator (not owned)
//
// public:
// my_ShortArray(bslma::Allocator *basicAllocator = 0);
// // Create an empty 'my_shortArray'. Optionally specify a
// // 'basicAllocator' used to supply memory. If 'basicAllocator'
// // is 0, the currently installed default allocator is used.
//
// my_ShortArray(const my_ShortArray& other,
// bslma::Allocator *basicAllocator = 0);
// // Create a 'bslma::ShortArray' having the same value as the
// // specified 'other' array. Optionally specify a 'basicAllocator'
// // used to supply memory. If 'basicAllocator' is 0, the currently
// // installed default allocator is used.
//
// ~my_ShortArray();
// // Destroy this object.
//
// // ...
// };
//
// // ...
//..
// In order to satisfy this contract, we will need a globally accessible
// utility (see 'bslma_default'), which by default returns the singleton
// 'bslma::NewDeleteAllocator', but which could be configured to return some
// other allocator, say a *test* allocator (see 'bslma_testallocator'):
//..
// // my_default.h:
// // ...
// namespace bslma { class Allocator; }
//
// struct my_Default {
// // This class maintains a process-wide 'bslma::Allocator' object
// // to be used when an allocator is needed, and not suppled explicitly.
// // By default, the currently installed default allocator is the unique
// // 'bslma::NewDeleteAllocator' object returned by the 'static' method,
// // 'bslma::NewDeleteAllocator::singleton()'. Note that the default
// // allocator will exist longer than any possibility of its use.
//
// static bslma::Allocator *allocator(bslma::Allocator *basicAllocator);
// // Return the address of the specified modifiable
// // 'basicAllocator' or, if 'basicAllocator' is 0, an instance of
// // the currently installed default 'bslma::Allocator' object, which
// // will exist longer than any possibility of its use. Note
// // that this function can safely be called concurrently (from
// // multiple threads).
//
// static bslma::Allocator *replace(bslma::Allocator *basicAllocator);
// // Replace the address of the currently installed allocator with
// // that of the specified modifiable 'basicAllocator' (or if 0,
// // with the "factory" default, 'bslma::NewDeleteAllocator'), and
// // return the address of the previous allocator. The behavior is
// // undefined unless 'basicAllocator' will exist longer than any
// // possibility of its use. Note that this function is *not* *at*
// // *all* thread-safe, and should *never* be called when multiple
// // threads are active.
// };
//
// // my_default.cpp:
// // ...
//
// #include <my_default.h>
//
// static bslma::Allocator *s_default_p = 0; // load-time initialized
//
// bslma::Allocator *my_Default::allocator(bslma::Allocator *basicAllocator)
// {
// return bslma::NewDeleteAllocator::allocator(s_default_p);
// }
//
// bslma::Allocator *my_Default::replace(bslma::Allocator *basicAllocator)
// {
// bslma::Allocator *tmp =
// bslma::NewDeleteAllocator::allocator(s_default_p);
// s_default_p = bslma::NewDeleteAllocator::allocator(basicAllocator);
// return tmp;
// }
//..
// Notice that the only part of the 'bslma::NewDeleteAllocator' class we used
// directly was its static 'allocator' method, which -- in addition to safely
// constructing the singleton 'bslma::NewDeleteAllocator' object on first
// access -- also automatically replaces a 0 address value with that of
// singleton 'bslma::NewDeleteAllocator' object. From now on, we will never
// again need to invoke the 'bslma_newdeleteallocator' component's interface
// directly, but instead use it through 'my_Default' (see 'bslma::Default' for
// what is actually used in practice).
//
// Turning back to our 'my_shortarray' example, let's now implement the two
// constructors using the 'bslma_newdeleteallocator' component indirectly via
// the 'my_default' component:
//..
// // my_shortarray.cpp:
// #include <my_shortarray.h>
// #include <my_default.h>
// #include <bsls_assert.h>
//
// // ...
//
// enum {
// INITIAL_CAPACITY = 0, // recommended to avoid unnecessary allocations
// // possibly resulting in locking and extra thread
// // contention for the 'bslma::NewDeleteAllocator'
//
// GROW_FACTOR = 2 // typical value for geometric growth
// };
//
// // ...
//
// my_ShortArray::my_ShortArray(bslma::Allocator *basicAllocator)
// : d_capacity(INITIAL_CAPACITY)
// , d_length(0)
// , d_allocator_p(my_Default::allocator(basicAllocator))
// {
// assert(d_allocator_p);
// d_array_p = (short *) // no thread contention if 'd_capacity' is 0
// d_allocator_p->allocate(d_capacity * sizeof *d_array_p);
// assert(0 == d_array_p);
// }
//
// my_ShortArray::my_ShortArray(const my_ShortArray& other,
// bslma::Allocator *basicAllocator)
// : d_capacity(other.d_capacity)
// , d_length(other.d_length)
// , d_allocator_p(my_Default::allocator(basicAllocator))
// {
// assert(d_allocator_p);
// d_array_p = (short *)
// d_allocator_p->allocate(d_capacity * sizeof *d_array_p);
// assert(!d_capacity == !d_array_p);
// memcpy(d_array_p, other.d_array_p, d_length * sizeof *d_array_p);
// }
//
// my_ShortArray::~my_ShortArray()
// {
// d_allocator_p->deallocate(d_array_p); // no locking if 'd_array_p' is 0
// }
//
// // ...
//..
// When the default constructor is called, the default capacity and length are
// recorded in data members via the initialization list. The static function
// 'allocator' (provided in 'my_Default') is used to assign the value of the
// 'basicAllocator' address passed in, or if that is 0, the address of the
// currently installed default allocator, which by default is the singleton
// object of type 'bslma::NewDeleteAllocator', defined in this component. Note
// that since 'INITIAL_CAPACITY' is 0, a default constructed object that is
// created using a 'bslma::NewDeleteAllocator' will *not* invoke the
// 'operator new' function, which on some platforms may needlessly acquire a
// lock, causing unnecessary overhead (the same potential overhead is avoided
// for 'operator delete' whenever a 0 'd_array_p' value is deallocated in the
// destructor) and 'd_allocator_p' refers to a 'bslma::NewDeleteAllocator'.
// Note also that, for the copy constructor, the currently installed default
// allocator, and not the 'other' array's allocator is used whenever
// 'basicAllocator' is 0 or not explicitly supplied.
//
// Finally note that this entire component is *not* intended for direct use by
// typical clients: See 'bslma_default' for more information or proper usage.
#include <bslscm_version.h>
#include <bslma_allocator.h>
namespace BloombergLP {
namespace bslma {
// ========================
// class NewDeleteAllocator
// ========================
class NewDeleteAllocator : public Allocator {
// This class defines a concrete mechanism that adapts the system-supplied
// (native) global 'operator new' and 'operator delete' to the 'Allocator'
// protocol. The class method 'singleton' returns a process-wide unique
// object of this class whose lifetime is guaranteed to extend from the
// first call to 'singleton' until the program terminates. A second class
// method, 'allocator', allows for conveniently replacing a "null"
// allocator with this singleton object. Note that this entire class
// should generally not be used directly by typical clients (see
// 'bslma_default' for more information).
private:
// NOT IMPLEMENTED
NewDeleteAllocator(const NewDeleteAllocator&);
NewDeleteAllocator& operator=(const NewDeleteAllocator&);
public:
// CLASS METHODS
static NewDeleteAllocator& singleton();
// Return a reference to a process-wide unique object of this class.
// The lifetime of this object is guaranteed to extend from the first
// call of this method until the program terminates. Note that this
// method should generally not be used directly by typical clients (see
// 'bslma_default' for more information).
static Allocator *allocator(Allocator *basicAllocator);
// Return the address of the specified modifiable 'basicAllocator' or,
// if 'basicAllocator' is 0, the process-wide unique (see 'singleton')
// object of this class. Note that the behavior of this function is
// equivalent to the following expression:
//..
// basicAllocator
// ? basicAllocator
// : &NewDeleteAllocator::singleton()
//..
// Also note that if a 'NewDeleteAllocator' object is supplied, it is
// owned by the class and must NOT be deleted. Finally note that this
// method should generally not be called directly by typical clients
// (see 'bslma_default' for more information).
// CREATORS
NewDeleteAllocator();
// Create a ("stateless") new-delete-allocator object that wraps the
// global native 'operator new' and 'operator delete' functions in
// order to supply memory via the 'Allocator' protocol. Note that all
// objects of this class share the same underlying resource; hence,
// this constructor should generally not be invoked directly by
// clients; instead, consider using the 'static' 'singleton' or
// 'allocator' (factory) methods, or -- better -- the appropriate ones
// in 'Default' (see 'bslma_default' for more information).
virtual ~NewDeleteAllocator();
// Destroy this allocator object. Note that destroying this allocator
// has no effect on any outstanding allocated memory.
// MANIPULATORS
virtual void *allocate(size_type size);
// Return a newly allocated block of memory of (at least) the specified
// positive 'size' (in bytes). If 'size' is 0, a null pointer is
// returned with no other effect. The alignment of the address
// returned is the maximum alignment for any fundamental, pointer, or
// enumerated type defined for this platform. The behavior is
// undefined unless '0 <= size'. Note that global 'operator new' is
// *not* called when 'size' is 0 (in order to avoid having to acquire a
// lock, and potential contention in multi-threaded programs).
virtual void deallocate(void *address);
// Return the memory block at the specified 'address' back to this
// allocator. If 'address' is 0, this function has no effect. The
// behavior is undefined unless 'address' was allocated using this
// allocator object and has not already been deallocated. Note that
// global 'operator delete' is *not* called when 'address' is 0 (in
// order to avoid having to acquire a lock, and potential contention in
// multi-threaded programs).
};
// ============================================================================
// INLINE DEFINITIONS
// ============================================================================
// ------------------------
// class NewDeleteAllocator
// ------------------------
// CLASS METHODS
inline
Allocator *NewDeleteAllocator::allocator(Allocator *basicAllocator)
{
return basicAllocator ? basicAllocator : &singleton();
}
// CREATORS
inline
NewDeleteAllocator::NewDeleteAllocator()
{
}
// MANIPULATORS
inline
void NewDeleteAllocator::deallocate(void *address)
{
// While the C++ standard guarantees that calling delete(0) is safe
// (3.7.3.2 paragraph 3), some libc implementations take out a lock to deal
// with the free(0) case, so this check can improve efficiency of threaded
// programs.
if (address) {
::operator delete(address);
}
}
} // close package namespace
#ifndef BDE_OPENSOURCE_PUBLICATION // BACKWARD_COMPATIBILITY
// ============================================================================
// BACKWARD COMPATIBILITY
// ============================================================================
typedef bslma::NewDeleteAllocator bslma_NewDeleteAllocator;
// This alias is defined for backward compatibility.
#endif // BDE_OPENSOURCE_PUBLICATION -- BACKWARD_COMPATIBILITY
} // close enterprise namespace
#endif
// ----------------------------------------------------------------------------
// Copyright 2013 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------