smart_ptr without memory allocation
I have a class that implements a buffer pool that allocates block of memory, and the users "free" the memory when it is no longer needed back to the buffer pool. Future allocations simply return the front of the free list. Simple enough, and the class returns shared_array<T> objects to automatically free the memory back into the proper buffer pool. The problem is, this mechanism is used so that during real-time operation (this is a real-time system), there is absolutely no memory allocations required. However, inside shared_array, it uses detail::shared_count and inside shared_count it performs a new to create a sp_counted_base object. So for every smart pointer object that supplies a deleter, it must perform a new. My proposal would be to include another constructor to both shared_array (and probably it's corresponding smart pointer brothers) and to shared_count that looks like: shared_array(T *p, sp_counted_base *d) : px(p), pn(d) { } shared_count(sp_counted_base *d) : pi_(d) { } (I haven't implemented this yet, so the above may not be quite right) The purpose of this is to supply an sp_counted_base object to the shared_* object that does the delete functionality. This eliminates the new in the case where a sp_counted_base object can be supplied. In the case of the managed buffer pool mentioned above, the sp_counted_base object could be allocated with the corresponding buffer, and then re-used for subsequent "allocations" from the free list. This should result in no dynamic allocations to create a shared_* object with a corresponding deleter. I hope this makes sense. It should only require two new constuctors. John
John Aughey wrote:
I have a class that implements a buffer pool that allocates block of memory, and the users "free" the memory when it is no longer needed back to the buffer pool. Future allocations simply return the front of the free list.
Simple enough, and the class returns shared_array<T> objects to automatically free the memory back into the proper buffer pool.
The problem is, this mechanism is used so that during real-time operation (this is a real-time system), there is absolutely no memory allocations required. However, inside shared_array, it uses detail::shared_count and inside shared_count it performs a new to create a sp_counted_base object. So for every smart pointer object that supplies a deleter, it must perform a new.
My proposal would be to include another constructor to both shared_array (and probably it's corresponding smart pointer brothers) and to shared_count that looks like:
shared_array(T *p, sp_counted_base *d) : px(p), pn(d) { }
shared_count(sp_counted_base *d) : pi_(d) { }
(I haven't implemented this yet, so the above may not be quite right)
The purpose of this is to supply an sp_counted_base object to the shared_* object that does the delete functionality. This eliminates the new in the case where a sp_counted_base object can be supplied. In the case of the managed buffer pool mentioned above, the sp_counted_base object could be allocated with the corresponding buffer, and then re-used for subsequent "allocations" from the free list. This should result in no dynamic allocations to create a shared_* object with a corresponding deleter.
I hope this makes sense. It should only require two new constuctors.
Yes, it makes perfect sense. Unfortunately it requires much more than just two new constructors. sp_counted_base would need to be documented; many shared_ptr operations would need to be respecified in terms of sp_counted_base operations. This is, of course, possible to do for boost::shared_ptr, but it would be unwise to overspecify std::tr1::shared_ptr in such a way, and I am reluctant to add features to boost::shared_ptr that have little chance to become standard. http://std.dkuug.dk/jtc1/sc22/wg21/docs/papers/2003/n1450.html There is one way to convince shared_ptr/shared_array to not allocate memory, although I'm not sure whether it can be applied to your environment as-is. First #define BOOST_SP_USE_QUICK_ALLOCATOR to make shared_ptr use <boost/detail/quick_allocator.hpp>. At startup, where presumably dynamic memory isn't strictly forbidden, instantiate a number of shared_ptr (or shared_array, it doesn't matter) objects using the appropriate deleter. This will make quick_allocator preallocate a number of pages (using ::operator new[]). Destroy the temporary shared_ptr objects. This sounds a bit painful, doesn't it. ;-) I'll think about streamlining the process. If you have any ideas please let us know.
participants (2)
-
John Aughey
-
Peter Dimov