Effective C++: 8 custom new and delete

Recommended for you: Get network issues from WhatsUp Gold. Not end users.
Eight, custom new and delete


In terms of 49: to understand the behavior of new-handler


When operator new cannot satisfy a memory allocation request, it throws a exception (abnormal). A long time ago, he returns a null pointer (null), and some of the old series


Translation is still do. You can still get the previous behavior (to some extent), but I want to end this Item talk about it.


In the operator new to respond to an insatiable memory request and throws a exception before, it first calls a specified by the customer are called new-handler error-handling


Function (error handling functions). (this is not entirely accurate, operator new really do things than the slightly more complicated, the details provided in Item 51. In order to specify the out-of-)


memory-handling function, Clients call set_new_handler -- one in <new> The standard library functions are declared in the:


namespace std {


typedef void (*new_handler)();
new_handler set_new_handler(new_handler p) throw();
}


As you can see, new_handler is a pointer to typedef, the pointer to function is not achieved and return anything, but set_new_handler is an acquisition and returns a


The function of new_handler. At the end of the set_new_handler statement ("); throw (" SPECIFICATION (exception is an exception specification). It basically says that this function will not throw


Any exception, though the truth is more interesting. For details, see Item 29. )


The set_new_handler parameter is a pointer to a function, this function should call operator new could not allocate the requested memory. Set_new_handler value is a pointer to the return;


Function pointer, the function is set_new_handler by the target effectively before call.


You can use a set_new_handler like this:


// function to call if operator new can't allocate enough memory
void outOfMem()
{
std::cerr <<"Unable to satisfy request for memory/n";
std::abort();
}
int main()
{
std::set_new_handler(outOfMem);
int *pBigDataArray = new int[100000000L];
...
}


If the operator new could not allocate space for 100000000 integers, outOfMem will be called, and the program will stop at issue an error information. (incidentally, consider if it was written


Memory error information to cerr... In must be dynamically allocated what will happen. )


When operator new cannot satisfy a memory request, it repeatedly calls new-handler function until it can find enough memory. These repeated calls to the code in Item 51 show


, But from this high level description is sufficient to derive a well designed new-handler function must do the following things one:


Make more memory available (make more memory available). This may make the operator new Nakanoshita Ichiji memory allocation success. A method of realizing this strategy is to start the program


Allocate a chunk of memory, then the new-handler was first called to release it for use.
Install a different new-handler (install a different new-handler). If the current new-handler can't make more memory available, it may have a different


New-handler can do. If so, the current new-handler can install another new-handler in its place (by set_new_handler). operator new


The next call to new-handler function, it will find that a recently installed. (a variation of this line is to make a new-handler to change its own behavior, so, the next time


It is called, you can do something different. One way to do that is to let new-handler change can affect the new-handler behavior of static (static), namespace-specific


(name space only) or global (global) data. )
Deinstall the new-handler (uninstall new-handler), that is, the null pointer to set_new_handler. No new-handler is installed, when the memory allocation failed when,


Operator new throws an exception.
Throw an exception (throws an exception), type bad_alloc or other types of inherited from bad_alloc. This will not be the exception operator new capture, so they will be spread


To issue memory requests.
Not return (no longer return), a typical case, call abort or exit.
These options enable you to have great flexibility in the implementation of new-handler functions.


Sometimes you may want to be assigned different object, different methods of dealing with memory allocation failure:


class X {
public:
static void outOfMemory();
...
};
class Y {
public:
static void outOfMemory();
...
};
X* p1 = new X; // if allocation is unsuccessful,
// call X::outOfMemory


Y* p2 = new Y; // if allocation is unsuccessful,
// call Y::outOfMemory


C++ Not for class-specific new-handlers support, but it does not need. You can implement this behavior. As long as you make every class and set_new_handler


Operator new its own version of your. Class set_new_handler allows customers to specify the new-handler for this class (as standard set_new_handler allows the customer to


Global new-handler). Class operator new to ensure that when the memory for class objects distribution, class-specific new-handler instead of global new-handler is that


Need .


Suppose you want to Widget class memory allocation failure. You must be aware of when the operator new was unable to function calls a Widget object to allocate enough memory, so you need to


Declare an new_handler of type static member (static members) to the class new-handler function. Widget looks like this:


class Widget {
public:
static std::new_handler set_new_handler(std::new_handler p) throw();
static void * operator new(std::size_t size) throw(std::bad_alloc);
private:
static std::new_handler currentHandler;
};


Static class members (static members of the class must be defined in the class definition) outside (unless they are const and integral -- see Item 2), so:


std::new_handler Widget::currentHandler = 0; // init to null in the class
// impl. file


The set_new_handler function in Widget will save any pointer passed to it, and any pointer is stored back to the previous call, and this is the standard version of the set_new_handler


Thing:


std::new_handler Widget::set_new_handler(std::new_handler p) throw()
{
std::new_handler oldHandler = currentHandler;
currentHandler = p;
return oldHandler;
}


Finally, Widget operator new will do the following things:


The Widget error-handling function parameter to invoke standard set_new_handler. This will install Widget new-handler for global new-handler.
Call global operator new actual memory allocation. If the allocation fails, global operator new Widget call new-handler, because the function had been installed for the


global new-handler. If the global operator new finally unable to allocate memory, it will throw a bad_alloc exception. In this case, Widget operator new


To restore the original global new-handler, and then spread the exception. In order to ensure that the original new-handler can always be restored, Widget global new-handler as a


Resources seriously, and follow the recommendations of Item 13, the use of resource-managing objects (resource management object) to prevent resource leaks (resource leaks).
If the global operator new to a Widget object allocates enough memory, Widget operator new returns a pointer to the allocated memory pointer. For the management of object


Global new-handler destructor (global new-handler destructor) will automatically restore to before calling the Widget operator new state.
The following is how you in a C+ + expression of all things in this. We start with the resource-handling class, part of the basic RAII operations (except in the construction process to obtain resources and analysis


Release in the process) (see Item 13), no more.:


class NewHandlerHolder {
public:
explicit NewHandlerHolder(std::new_handler nh) // acquire current
:handler(nh) {} // new-handler


~NewHandlerHolder() // release it
{ std::set_new_handler(handler); }
private:
std::new_handler handler; // remember it


NewHandlerHolder(const NewHandlerHolder&); // prevent copying
NewHandlerHolder& // (see Item 14)
operator=(const NewHandlerHolder&);
};


This makes Widget operator new implementation is very simple:


void * Widget::operator new(std::size_t size) throw(std::bad_alloc)
{
NewHandlerHolder // install Widget's
h(std::set_new_handler(currentHandler)); // new-handler


return ::operator new(size); // allocate memory
// or throw


} // restore global
// new-handler


Widget clients like new-handling capabilities to use it (the ability to handle new):


void outOfMem(); // decl. of func. to call if mem. alloc.
// for Widget objects fails


Widget::set_new_handler(outOfMem); // set outOfMem as Widget's
// new-handling function


Widget *pw1 = new Widget; // if memory allocation
// fails, call outOfMem


std::string *ps = new std::string; // if memory allocation fails,
// call the global new-handling
// function (if there is one)


Widget::set_new_handler(0); // set the Widget-specific
// new-handling function to
// nothing (i.e., null)


Widget *pw2 = new Widget; // if mem. alloc. fails, throw an
// exception immediately. (There is
// no new- handling function for
// class Widget.)


No matter what class is, the program code is the same, so in other places to reuse it is a reasonable goal. To make it a simple method is to create a "mixin-


style" base class("Hybrid wind "base class), that is to say, a design to allow derived classes (derived) inherited a single specific capacity (in the current circumstances, is to set a


The ability of a class-specific new-handler class (base) of the base class). Then the base class (base) into a template (template), so you get to


Each inheriting class (inherited class) different copies of class data.


The design of the base class (base) to classes (derived derived class inherits all of them) to set_new_handler and operator new functions, and this design


Template (template) part to ensure that every inheriting class (inherited class) has a different currentHandler data member (data members). This may sound a bit complicated


, But the code looks reliable and familiar. In fact, the only real difference is it can be used in any need it class now:


template<typename T> // "mixin-style" base class for
class NewHandlerSupport{ // class-specific set_new_handler
public: // support


static std::new_handler set_new_handler(std::new_handler p) throw();
static void * operator new(std::size_t size) throw(std::bad_alloc);


... // other versions of op. new —
// see Item 52
private:
static std::new_handler currentHandler;
};


template<typename T>
std::new_handler
NewHandlerSupport<T>::set_new_handler(std::new_handler p) throw()
{
std::new_handler oldHandler = currentHandler;
currentHandler = p;
return oldHandler;
}


template<typename T>
void* NewHandlerSupport<T>::operator new(std::size_t size)
throw(std::bad_alloc)
{
NewHandlerHolder h(std::set_new_handler(currentHandler));
return ::operator new(size);
}
// this initializes each currentHandler to null
template<typename T>
std::new_handler NewHandlerSupport<T>::currentHandler = 0;


With this class template (template), add set_new_handler support for Widget is very easy: Widget only need from NewHandlerSupport<Widget> Inheritance can be. (


It may seem strange, but I will explain in more detail. )


class Widget: public NewHandlerSupport<Widget> {
... // as before, but without declarations for
}; // set_new_handler or operator new


These are the Widget in order to provide a class-specific set_new_handler need to do all.
But maybe you still from Widget to NewHandlerSupport<Widget> Inheritance and trouble. If so, when you notice the NewHandlerSupport template never use it


Type parameter T, you may be more trouble. It don't need to do that. All we need is for each inherited from the NewHandlerSupport class provides a different


NewHandlerSupport -Especially for its static data member (static data members) copies of currentHandler -- the. Template parameter T just to be a


Inheriting class and another distinguished. Template mechanism automatically for each copy instantiated in NewHandlerSupport T to generate a currentHandler.


For the Widget from a Widget as a type parameter (the type parameter templatized (base) class template class) inheritance, if this concept is making you a bit confused


, Don't be sad. It began to have such an effect on everyone. However, it has developed into a technology is so useful, it has a name, though it normally looks reflected the fact that is not the first time they


See what it looks like. It is called the curiously recurring template pattern (recursive template pattern peculiar) (CRTP). Forsooth .


At this point, I published an article suggesting a better name called " Do It For; Me", because when the Widget from NewHandlerSupport<Widget> Inheritance, it is in fact the said: "I


Is Widget, and I want to inherit from NewHandlerSupport class to Widget." No one is using my proposed name (even myself), but the CRTP consider this "do it


for me" One approach might help you understand templatized inheritance (template inheritance) in what to do.


Like NewHandlerSupport, templates allows for any class add a class-specific new-handler become easy. Yet , mixin-style


Inheritance (hybrid wind inheritance) always leads to multiple inheritance (multiple inheritance) topic, but before we move along this path, you need to read the Item 40.


Until 1993, C+ + also called operator new cannot assign requested memory to return null. Operator new now designated throws a bad_alloc exception, but a lot of


C++ The program is started before the revision of the standard support in the compiler. C+ + Standardization Committee did not want to abandon the test-for-null (test whether null) code base, so they provide


Another form of the optional operator new, used to provide traditional failure-yields-null (failure behavior of null). These forms are called " nothrow" form, which in a certain degree


Because of their use in the new areas use nothrow objects (defined in the header file <new> Centre .:


class Widget { ... };
Widget *pw1 = new Widget; // throws bad_alloc if
// allocation fails


if (pw1 == 0) ... // this test must fail


Widget *pw2 =new (std::nothrow) Widget; // returns 0 if allocation for
// the Widget fails


if (pw2 == 0) ... // this test may succeed


The exception, nothrow new provides looks less than the original mandatory guarantee. The expression of " new (std:: nothrow) Widget", two things happened. First of all, operator new


The nothrow version is called a Widget object to allocate enough memory. If the allocation fails, as everyone knows, operator new returns null pointer. However, if it is successful


, Widget constructor is called, but at this moment, all the betting fails. Widget constructor can do anything it wants. It may be your new out some memory, and if it


To do so, it was not forced to use nothrow new. So, although in the " new (std:: nothrow) Widget" operator new calls will not throw, Widget constructor


Sure. If it does, exception as usual be spread. Conclusion the use of nothrow? New operator new can only guarantee will not throw, cannot guarantee a like "new


(std::nothrow) Widget" Such expressions will not lead to a exception. In all probability, you'd never need to nothrow NEW.


Whether you are using " normal" (i.e., exception-throwing) new, or its slightly dysplastic nothrow, understand new-handler behavior is very important, because it can be


For two kinds of forms.


Please remember:
Set_new_handler allows clients to specify a function, can not be met calls in the memory allocation.
Nothrow new is a rather limited tool, because it applies only to the memory allocation; constructor calls the successor or might throw an exception.




In terms of 50: to understand new and delete reasonable replacement time


Why would anyone want to replace the compiler provides operator new or operator delete? We can list the following three common reasons:
■ For error detection application.
The programmer from start to debug the code until the final completion of this process, make all sorts of mistakes can hardly be avoided, these errors may be
Cause memory leaks (memory leaks), uncertain behavior, overruns (written in allocation block after underruns (end), write point
In the distribution of block end before) and other adverse results. If we custom operator news, we can use the amount of excess memory allocation, outer space
The placement of specific signatures to detect problems.
■ In order to strengthen the effectiveness.
We use the compiler with operator new and operator delete is mainly used for general purpose can provide various types of programs
To accept, without considering the specific type of program. They must deal with a series of demand, must accept all kinds of distribution form, must consider the fragmentation problem and so on
These problems, so the compiler with operator new and operator delete to take a middle course is no way things. They work for each
People are reasonably good, but no specific anyone has the best performance. Can usually be found, a customized version of operator new and operator delete
To overcome the default version. The so-called 'rather than', is that they are relatively fast, sometimes much faster, but they require less memory, highest can save 50%, the
To say for some applications, will replace the default new and delete for customized version, is one of the major performance improvement measures.
■ In order to use statistical data collection.
Collect your software to use the dynamic memory allocation block size. Released? Life released? They tend to FIFO sequence or LIFO
Order and random order to allocate and deallocate? They use whether the shape change with time, that is your software has different distribution in different stages
/Return the form? What is the maximum amount of dynamic memory allocation using any moment? Their own definition of the operator new and operator delete makes us
To be relaxed to collect these information.
Based on the above three reasons, I had to start writing a custom operator new, my first draft look like the following code is shown, which also.
In many small mistake, I'll fix it later.
typedef const int signature = 0xDEADBEEF;
typedef unsigned char Byte;
void* operator new( std::size_t size)throw(std::bad_alloc)
{
using namespace std;
size_t real_size = size + 2 * sizeof(int);

void* applied_memory = malloc( real_size );
if( applied_memory == 0 ){
throw bad_alloc();
}
//The signature into memory the most before the paragraphs and the last paragraph.
*(static_cast<int*>( applied_memory ) = signature;
*(reinterpret_cast<int*>(static_cast<Byte*>( applied_memory )
+ real_size - sizeof(int) ) ) = signature;

//The returned pointer, pointing to is in after the first signature memory location.
return static_cast<Byte*>( applied_memory ) + sizeof(int);
}
As I have said, this version has many problems. Now I just want to focus on a more subtle theme: Qi bit (alignment). A bit out of Qi
What is the body? I assume you already know, I will not nag about here. Because the C+ + pointer requires that all the operator news returns have
Proper alignment (depends on the type of data).Malloc is working under such request, so that operator new returns a malloc finger
The needle is safe. However, the operator new I did not return a pointer from malloc, it returns a malloc and an offset
The pointer int size. No one can guarantee the safety of it! We may use the version of the operator new to obtain a no proper Qi bit
The pointer. It may cause the program to crash or slower execution. In either case is not what we want to see results.
Is not difficult to write a can always run the memory manager, difficult is it to good operation. Generally speaking, the author suggest that you need
Later try to write. Many times this is not necessary. Some compilers already in memory management functions in which they switch to debug state and state of mind
At a quick glance at your compiler documentation, possibly eliminates the need for you to write new and delete.
Another option is the memory manager open source fields. They are available for many platforms, you can try to download the.Boost library Pool
This is a distributor, it is helpful to.TR1 support various types of special alignment condition, common for the large number of small objects' distribution 'is value get noticed.
Discussion here, we can discuss the question reason for this paragraph at the beginning of the addition of a few, ha ha:
■ In order to increase the allocation and return rate.
Universal distributor more often than custom allocator is slow, especially when the custom type distributor specifically for a particular type of object and design.
■ The space overhead for reducing the default memory manager.
Universal memory manager often use more memory, it is because they are often used in each allocation block body attract some extra overhead.
■ In order to make up the default allocator in non best Qi.
■ In order to locate relevant objects (detail).
■ In order to obtain non traditional behavior (detail).
OK,our topic talk is over!


Please remember:
There are many reasons to write a custom new and delete, including improved efficiency, the use of heap error debugging, collecting heap information.




The terms new and delete 51: prepared to stick to routine


The previous terms we have discussed you want to write a custom in what time operator new and operator delete, but did not explain when you do what I must abide by the rules. First come in general a


Next, and then the analysis of these rules.
In order to realize the consistency of operator new will return the correct value, memory will call the new-handling function (see clause 49), must deal with zero memory requirements of preparation, also need to avoid accidentally hide it


Common forms of new (although it is near class interface requirements and non implementation of the requirements).
First talk about the return value if it has the ability to supply customers, application memory, it returns a pointer to the block of memory. If you don't have that ability, will follow 49 principles described, and throws a bad_alloc


Unusual .
In fact operator new tried more than once to memory allocation, and in every failure after calling the new-handing function. This assumes that new-handling function may be able to do certain movements in the release of some


Pointer to a new-handling function. Only when the current is null, the operator new will throw an exception.
C++Regulations, even if the customer requirements 0bytes, operator new must return a valid pointer. This strange behavior is to other parts of the simplified language. Below is a non-member operator


New code:
void* operator new(std::size_t size) throw(std::bad_alloc)
{
using namespace std;
if( size == 0 ){
size = 1;
}
while( true ){
...//try to allocate size bytes memory.
if( allocate_succeed ){
return (point_to_allocted_memory);
}
//allocate failed:find current new-handling function(as following)
new_handler global_handler = set_new_handler( 0 );
set_new_handler( global_handler );

if( global_handler ){
( *global_handler )();
} else {
throw std::bad_alloc();
}
}
}
Now we consider here a possible problem: many people are not aware of the operator new member function will be derived classes inheritance, it would appear, there may be base class


Operator new is called to allocate derived class objects:
struct Base{
static void* operator new(std::size_t size) throw( std::bad_alloc );
...
};
struct Derived:public Base{...};
Derived* p = new Derived;//call Base::operator new.
If the Base class exclusive operator new is not designed to deal with the above situation (in fact it is usually true), best practices for dealing with this situation is called behavior will 'memory application error' adopt standard


operator new,Like this:
void* Base::operator new(std::size_t size) throw(std::bad_alloc)
{
if( size != sizeof(Base) ){
return ::operator new( size ); //call standard operator new version.
}
...
}
If you want to control class exclusive'arrays memory allocation behavior ', then you need to implement the operator new array operator new[]. brothers version: This is usually referred to as " array new". If


You should write the operator new[], remember, the only thing to do is to allocate a block of memory. Because unprocessed element object you have so far been unable to within array are actually you do anything.


Even can not calculate the array will contain many elements. First, you don't know how much of each object, so you can't in Base:: operator new[] assumes that each element object size is sizeof (Base), in addition


The parameter passed to size it value probably 'will be filled with the amount of memory objects' more.
This is to write operator new when you need to pursue the rule.Operator delete is more simple, you need to remember that the only thing that C+ + guarantee 'delete null safe forever', so you


You must fulfill this guarantee. The pseudo code below is the non-member operator delete:
void operator delete( void* raw_memory ) thrwo()
{
if( raw_memory == 0 ){
return;
}
...//now,free raw memory block.
}
For the member version is also very simple.
void Base::operator delete( void* raw_memory,std::size_t size ) throw()
{
if( raw_memory == 0 ){
return;
}
if( size != sizeof(Base) ){ //if size error, call standard operator delete
::operator delete( raw_memory );
return;
}
...//now,free your raw memory block.
return;
}
If the deleted object derived from a base class while the latter lacks the Virtaul destructor, then the C+ + to size_t number value operator delete; may not be correct. This is' let your base


A good enough reason class has the virtual destructor '.


Please remember:
Operator new should contain an infinite loop, and in which attempts to allocate memory, if it is unable to meet the demand for memory, should call new-handler.
It should also have the ability to handle 0bytes for.Class exclusive version also should handle 'more than the correct size (error) application'.
Operator delete should anything.Class exclusive versions do not received in the null pointer is also should handle 'more than the correct size (error) application'.




Clause 52: wrote placement new to write placement delete


We all know that when you write a new expression like this:
Widget* new_widget = new Widget;
A total of two function is called: one is used to allocate memory for operator new, a Widget default constructor.
Suppose we meet now the situation is: the first call success, second function can throw an exception. As a rule, the distribution in step one in
Memory must cancel, otherwise it will cause memory leaks. And at this time the customer has no ability to return the memory, because the memory does not point to a hand.
The pointer, so it fell to the C+ + on the run time system.
In order to complete the task, operator new certainly will invoke step the runtime system corresponding to the operator version of delete. If the current to
Science is to have normal signature new and delete version, it's easy! Because the operator new signature normal:
void* operator new(std::size_t) throw (std::bad_alloc);
The normal operator delete signature:
void operator delete(void* raw_memory)throw();//Normal signature global in scope
void operator delete(void* raw_memory,std::size_t size)throw();//Signature of typical class scope
Therefore, when you use the normal forms of new and delete, a runtime system without problems can find the 'know how to cancel the doings and new.
View restoration 'delete. but when you start to declare non normal form of operator new, which is the additional parameters of operator new, the problem came out.
In order to explain this question, still with our Widget example, suppose that you write a class exclusive operator new, asked to accept a ostream,
For logged assignment information, also wrote a normal form class exclusive operator delete:
struct Widget{
//Non normal form of new
static void* operator new(std::size_t size,std::ostream& log_stream)throw(std::bad_alloc);
//Normal class exclusive delete.
static void operator delete(void* memory, std::size_t size)throw();
...
};
Here we define: if the parameter operator new accept except there will be the size_t other, this is called
Placement new. and many of the placement version of new with particular reference to 'accept a pointer to the object should be constructed in', so
Operator new looks as follows:
void* operator new( std::size_t, void* memory ) throw();//placement new
This version of new has been incorporated into the C+ + standard library, as long as you#include <new>You can take it, it is not responsible for vector
The use of space to create objects.
Declarative now let us return to the Widget, the Widget will cause subtle memory leaks. Considering the test code below, it will create a dynamic
Widget will be related to the distribution of information description and cerr:
Widget* new_widget = new( std::cerr ) Widget;
What we mentioned previously in that, if the memory allocation succeeds, and constructs throws an exception, operation period has the responsibility to cancel the distribution of new and operator
To restore the old concept. However, runtime system cannot know how true is that operator new calls the operation, so it cannot cancel the distribution and repair, so
This approach will not work. Replace sb. is, a operator runtime system for 'the number of parameters and type are the same as operator new'
Delete. if the call, that's it. Since the calling object types here operator new accepted ostream& additional arguments, so the corresponding
Operator delete should be:
void operator delete(void*,std::ostream&)throw();
like in the new version of placement operator delete, if you accept the additional parameters, is called placement deletes. now, since Widget
No statement of placement version of the operator delete, so the runtime system does not know how to cancel and restore the original placement new calls.
What not to do. In this case, if the construction throws an exception, no operator delete is called.
In order to eliminate the memory leak in Widget, we declare a Palcement delete, corresponding to the description of function of placement new:
struct Widget{
static void* operator new(std::size_t size, std::ostream& log_stream)throw(std::bad_alloc);
static void operator delete(void* memory) throw();
static void operator delete(void* memory,std::ostream& log_stream)throw();
...
};
Such changes, if the following statement causes the Widget constructor throws an exception:
Widget* new_widget = new (std::cerr) Widget; //As in the past, but this was not in the event of a leak.
However, if no exceptions (most of it), there is a corresponding delete client code, what will happen:
delete pw; //call normal operator delete
Call the normal form of the operator delete, rather than the placement version. Please remember: placement delete only in the 'with placement
The constructor call 'new trigger abnormal will be invoked. To a pointer to the implementation of delete will not cause the call to placement delete.
Another thing you need to pay attention to is: because the name of member function will cover the same name its enclosing scope, you must be careful to avoid letting class exclusive
Other news news cover customer expectations (including normal version). By default, the C+ + provide the following forms of operator new in global domain:
void* operator new(std::size_t)throw(std::bad_alloc);//normal new.
void* operator new(std::size_t,void*)throw();//placement new
void* operator new(std::size_t, const std::nothrow_t&)throw();//nothrow new.see Item 49.
If you declare any operator news in the class, it will cover these standards. Unless you mean to stop class customers to make
With these forms, otherwise please ensure that they are outside your generated any custom operator new is also available. For each of the available operator new
Please make sure to provide the corresponding operator delete. if these functions are the usual behavior, as long as the class exclusive version of your calls the global version
This can be.
A simple approach to the completion of the above said, is to build a base class, containing all the normal forms of new and delete:
struct StandardNewDeleteForms{
//normal new/delete
static void* operator new(std::size_t size)throw(std::bad_alloc)
{ return ::operator new( size ); }
static void operator delete(void* memory) throw()
{ ::operator delete( memory ); }
//placement new/delete
static void* operator new(std::size_t size,void* pointer)throw()
{ return ::operator new( size, pointer );}
static void operator delete(void* memory,void* pointer)throw()
{ return ::operator delete( memory, pointer ); }
//nothrow new/delete
static void* operator new(std::size_t size,const std::nothrow_t& no_throw)throw()
{ return ::operator new( size, no_throw ); }
static void operator delete(void* memory,const std::nothrow_t&)throw()
{ ::operator delete( memory ); }
};
Those who want to self expansion of form standard forms of customer, can make use of the inheritance mechanism and using declarative (Item 33) has been the standard form:
struct Widget:public StandardNewDeleteForms{
using StandardNewDeleteForms::operator new;
using StandardNewDeleteForms::operator delete;
static void* operator new(std::size_t size, std::ostream& log_stream) throw(std::bad_alloc);
static void operator delete(void* memory,std::ostream& log_stream) throw();
...
};


Please remember:
When you write a placement operator new, please be sure to write the corresponding placement operator delete. if you do not, your program may be cryptic and intermittent memory leak


.
When you declare placement new and placement delete, please make sure not to unconsciously cover normal versions of them.
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download

Posted by Boris at December 18, 2013 - 3:50 AM