Valid tive C ++ clause 52: If you have entered placement new, you must also enter placement Delete.

Source: Internet
Author: User

Widget * PW = new widget;

Two functions are called: Operator New for memory allocation and default constructor for widgets.

Assume that the first call is successful, but the second one throws an exception. In step 1, the allocated memory must be canceled and restored. Otherwise, memory leakage may occur. At this time, the customer is unable to return the memory, because the widget constructor throws an exception, PW has not been assigned a value, and the customer has no pointer to the returned memory. If you cancel Step 1 and restore the old view, the C ++ operating system will be responsible.

During runtime, the system will happily call the corresponding operator Delete version of operator new called in step 1, provided that he must know which operator Delete is called (there may be many ). If you are currently dealing with new and delete with normal signatures, it is not a problem. Normal New:

Void * operator new (STD: size_t) Throw (STD: bad_alloc );

Corresponding to the normal delete:

Void operator Delete (void * rawmemory) Throw (); // normal signature in the global scope

Void operator Delete (void * rawmemory, STD: size_t size) Throw (); // typical signature type in the class scope.

But when you begin to declare an abnormal form of operator new, that is, operator new with additional parameters, the question of "which delete is accompanied by this new" emerges:

The class-specific operator New requires an ostream to log the allocation information and write a normal form of class-specific operator Delete:

Class widget {
Public:
Static void * operator new (STD: size_t size, STD: ostream & logstream) Throw (STD: bad_alloc );
Static void * operator Delete (void * pmemory, STD: size_t size) Throw ();
};

If operator new accepts all the parameters except the size_t, this is the so-called placement new, one of the many placement new is "accepting a pointer pointing to the object to be constructed". The operator new looks as follows:

Void * operator new (STD: size_t, void * pmemory) Throw ();

This version has been incorporated into the C ++ standard library and can be used as long as # include <New>. One of the purposes of this new method is to create objects in the unused space of the vector. He is also the earliest placement new version. The name of this function is based on the new in a specific position.

Widget * PW = new (STD: cerr) widget;

If the widget constructor throws an exception, the system cannot know how the called New Function operates during the runtime. Therefore, the distribution cannot be canceled and the old view cannot be restored. During the runtime, the system finds an operator Delete with the same number and type as operator new. It should be:

Void operator Delete (void *, STD: ostream &) Throw ();

It is called Placement deletes. Now, since the widget does not declare the operator delete of the placement version, the runtime system does nothing. If the widget constructor throws an exception, no operator Delete is called.

The rule is simple: If an operator new with additional parameters does not have the corresponding operator Delete with the same additional parameters, when the new memory allocation action needs to be canceled and restored, no operator Delete will be called. Therefore, it is necessary to declare a placement Delete, which corresponds to the placement new with the log function:

Class widget {
Public:
Static void * operator new (STD: size_t size, STD: ostream & logstream) Throw (STD: bad_alloc );
Static void * operator Delete (void * pmemory, STD: size_t size) Throw ();
Static void * operator Delete (void * pmemory, STD: ostream & logstream) Throw ();
};

After this change, if the widget constructor throws an exception:

Widget * PW = new (STD: cerr) widget;

The corresponding placement Delete is automatically called, giving the widget the opportunity to ensure that the memory is not leaked.

This statement:

Delete PW; // call the normal operator Delete

Placement Delete is called only when an exception occurs in the constructor triggered by the call of placement new. Executing a delete operation on a pointer will never cause the call to placement Delete.

This means that for all placement new, we must provide a normal delete and a placement version at the same time.

Because the name of the member function masks the same name in its peripheral scope, you must carefully make the class-specific news mask other news (including normal versions) that the customer expects ).

If you have a base class that declares the only placement operator new, the customer will find that they cannot use the normal form of New:

Class base {
Public:
Static void * operator new (STD: size_t size, STD: ostream & logstream) Throw (STD: bad_alloc );
};

Base * pb = new base; // error. Operator new in normal format is masked

Base * pb = new (STD: cerr) base; // correct, call palcement new

Similarly, operator new in Derived classes masks the global version and the inherited operator new version:

Class derived: public base {
Public:
Static void * operator new (STD: size_t size) Throw (STD: bad_alloc); // re-declare the normal form of new
};

Derived * Pd = new (STD: cerr) derived; // The base placement new is masked
Derived * Pd = new derived; // correct,

By default, C ++ provides the following operator new in the global scope:

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

If you declare any operator news in the class, it will mask these standard forms. Unless you mean to prevent class customers from using these forms, make sure they are available in addition to any custom operator new you generate.

A simple method is to create a base class that contains all normal forms of new and delete:

Class standardnewdeleteforms {
Public:
// Normal New/delete
Static void * operator new (STD: size_t size) Throw (STD: bad_alloc)
{Return: Operator new (size );}
Static void operator Delete (void * pmemory) Throw ()
{: Operator Delete (pmemory );}
// Placement new/delete
Static void * operator new (STD: size_t size, void * PTR) Throw ()
{Return: Operator new (size, PTR );}
Static void operator Delete (void * pmemory, void * PTR) Throw ()
{Return: Operator Delete (pmemory, PTR );}
// Nothrow new/delete
Static void * operator new (STD: size_t size, const STD: nothrow_t & NT) Throw ()
{Return: Operator new (size, NT );}
Static void operator Delete (void * pmemory, const STD: nothrow_t &) Throw ()
{: Operator Delete (pmemory );}
};

Any customer who wants to expand the standard form in a custom form can use the Inheritance Mechanism and the using declarative form to obtain the standard form:

Class Widget: Public standardnewdeleteforms {
Public:
Using standardnewdeleteforms: Operator new;
Using standardnewdeleteforms: Operator Delete;
Static void * operator new (STD: size_t size, STD: ostream & logstream) Throw (STD: bad_alloc );
Static void operator Delete (void * pmemory, STD: ostream & logstream) Throw ();
};

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.