Example 11-50 shows a method to replace new
and delete
. As described in Chapter 6, all versions of new
and delete
must be replaced at once, which amounts to four versions of new
and four versions of delete
. It is necessary to link with the scalable memory library (see Chapter 6).
Please note that you do not have to initialize the task scheduler to be able to use the memory allocator. We do initialize it in this example because it uses parallel_for
in order to demonstrate the use of memory allocation and deallocation in multiple tasks. Similarly, the only header file that is required for the memory allocator is tbb/scalable_allocator.h.
There are four basic signatures for new
and delete
: a set for individual objects, and a set for arrays of objects. If memory cannot be allocated, new
calls the new handler function if set, or it throws the std::bad_alloc()
exception. This example chooses to ignore any new handler because there are thread-safety issues (see the sidebar “Thread-Safety Issues in Implementing new”), and it always throws std::bad_alloc()
. The variation of the basic signature includes the additional parameter const std:: nothrow_t&
that means that this operator will not throw an exception but will return NULL
if the allocation fails. These four non-throwing exception operators can be used for C runtime libraries. See Example 11-51 for a driver program that also demonstrates the replacement of new
and delete
.
Example 11-50. Replacement of new and delete functions, demonstration
#include "tbb ask_scheduler_init.h" #include "tbblocked_range.h" #include "tbbparallel_for.h" #include "tbbscalable_allocator.h" // No retry loop because we assume that scalable_malloc does // all it takes to allocate the memory, so calling it repeatedly // will not improve the situation at all // // No use of std::new_handler because it cannot be done in portable // and thread-safe way (see sidebar) // // We throw std::bad_alloc() when scalable_malloc returns NULL //(we return NULL if it is a no-throw implementation) void* operator new (size_t size) throw (std::bad_alloc) { if (size == 0) size = 1; if (void* ptr = scalable_malloc (size)) return ptr; throw std::bad_alloc (); } void* operator new[] (size_t size) throw (std::bad_alloc) { return operator new (size); } void* operator new (size_t size, const std::nothrow_t&) throw () { if (size == 0) size = 1; if (void* ptr = scalable_malloc (size)) return ptr; return NULL; } void* operatornew[] (size_t size, const std::nothrow_t&) throw ( ) { return operator new (size, std::nothrow); } void operator delete (void* ptr) throw ( ) { if (ptr != 0) scalable_free (ptr); } void operator delete[] (void* ptr) throw ( ) { operator delete (ptr); } void operator delete (void* ptr, const std::nothrow_t&) throw ( ) { if (ptr != 0) scalable_free (ptr); } void operator delete[] (void* ptr, const std::nothrow_t&) throw ( ) { operator delete (ptr, std::nothrow); }
Example 11-51. Driver program to demonstrate replacement of new and delete
class do_for { const size_t chunk; public: do_for (size_t _chunk): chunk (_chunk) {} void operator( ) (tbb::blocked_range<int> &r) const { for (int i = r.begin(); i != r.end( ); ++i) { // scalable_malloc will be called to allocate thememory // for this array of int's int *p = new int [chunk]; // scalable_free will be called to deallocate the memory // for this array of int's delete[] p; } } }; int main (int argc, char** argv) { const size_t size = 1000; const size_t chunk = 10; const size_t grain_size = 200; // Initialize TBB tbb::task_scheduler_init tbb_init; // scalable_malloc will be called to allocate the memory // for this array of int's int *p = new int[size]; tbb::parallel_for (tbb::blocked_range<int> (0, size, grain_size), do_for (chunk)); return 0; }
3.144.124.232