Reading Notes Objective c ++ Item 51 must comply with the Conventions when implementing new and delete.

Source: Internet
Author: User
Tags class operator

Reading Notes Objective c ++ Item 51 must comply with the Conventions when implementing new and delete.

Item 50 explains under what circumstances you may want to implement operator new and operator delete in your own version, but does not explain the conventions you need to follow when implementing it. It is not difficult to follow these rules, but some of them are not intuitive, so it is important to know what these rules are.

1. Definitions of operator new conventions 1.1 Conventions list

We start with operator new. To implement a consistent operator new, you must haveCorrect Return ValueWhen there is not enough memoryCallNew-handlingFunction(See Item 49) and be preparedHandle situations where no memory can be allocated. You also want to avoid hiding the new version of "normal" without any reason, but this is a class interface problem rather than a requirement problem; it will be processed in Item 52.

The return value of Operator new is very simple, because operator new will actually try to allocate memory multiple times and call the new-handling function after the internal allocation fails. The assumption here is that the new-handling function may do something to release some memory. Operator new throws an exception only when the pointer to the new-handling function is null.

Curiously, C ++ needs operator new to return a valid pointer even when requesting 0 bytes. (This strange requirement simplifies some things in the language .) This is the basic situation. A non-member operator new pseudo code will look like the following:

 1 void* operator new(std::size_t size) throw(std::bad_alloc) 2 { // your operator new might 3  4 using namespace std;             // take additional params 5  6 if (size == 0) {          // handle 0-byte requests 7  8  9 size = 1; // by treating them as10 } // 1-byte requests11 while (true) {12 attempt to allocate size bytes;13 14 if (the allocation was successful)15 return (a pointer to the memory);16 // allocation was unsuccessful; find out what the17 // current new-handling function is (see below)18 new_handler globalHandler = set_new_handler(0);19 set_new_handler(globalHandler);20 if (globalHandler) (*globalHandler)();21 else throw std::bad_alloc();22 }23 }

 

It seems annoying to use 0 bytes as one byte in a request, but this is simple and legal and can work, no matter what, how frequently will your requests for 0 bytes be?

You may seem skeptical about setting the new-handling function pointer to null in pseudo code and then quickly restoring it. Unfortunately, there are no other methods to directly obtain the pointer of the new-handling function, so you must call set_new_handler to find out what this function is. It looks rough but effective, at least for a single thread. In a multi-threaded environment, you may need some type of lock to safely operate the (global) data structure behind the new-handling function.

As discussed in Item 49, operator new contains an infinite loop, which is displayed in the code above. "while (true)" indicates an infinite loop. The only way to exit the loop is to successfully allocate memory or let the new-handling function do one of the items described in Item 49:There is more memory available for allocation, install a differentNew-handler, UninstallNew-handler, Throws an exception, which either inherits fromBad_allocOr the error is returned.. Now you should know why new-handler must do one of these things. If it cannot, the loop in operator new will never end.

1.2 issues caused by inheritance

Many people do not realize that the operator new member function is inherited by the derived class. This may lead to some interesting complications. In the pseudo code of operator new above, note that the function tries to allocate size bytes. This is reasonable because it is a parameter passed to the function. However, as explained in Item 50, the most common reason for implementing a custom Memory Manager isObjects of a specific classOptimize the memory allocation, rather than the class or any of its derived classes. That is to say, we provide operaor new for class X. The behavior of this function is to adjust the size of an object that is exactly sizeof (X), that is, not big or small. However, because of inheritance, it is possible to allocate memory for the derived class object by calling operator new in the base class:

1 class Base {2 public:3 static void* operator new(std::size_t size) throw(std::bad_alloc);4 ...5 };6 class Derived: public Base // Derived doesn’t declare7 { ... }; // operator new8 9 Derived *p = new Derived;                             // calls Base::operator new!

 

 

If the operator new design in the base class does not handle this situation, the best way to handle it will discard requests with "error" memory, but instead use the standard operator new for processing, as shown below:

 1 void* Base::operator new(std::size_t size) throw(std::bad_alloc) 2  3 { 4  5  6 if (size != sizeof(Base)) // if size is “wrong,” 7 return ::operator new(size); // have standard operator 8 // new handle the request 9 ... // otherwise handle10 // the request here11 }

 

"Wait," I heard you yell. "You forgot to check the symptoms, but what may happen, that is, the size is 0 !" In fact, I did not forget. The test is still there, except that the test is incorporated into the test with the same size as sizeof (size. C ++ works in a mysterious way. One of the methods is to specify that the size of all independent objects cannot be 0 (see Item 39 ). As defined, sizeof (Base) will never be 0, so if size is 0, memory requests will be processed by: operator new, it will process the request in a reasonable way.

 

1.3 define operator new [] Conventions

 

If you want to control the memory allocation of arrays in a class, you need to implement the array form of operator new []. (This function is usually called "array new" because it is difficult to determine how to pronounce "operator new ). If you decide to implement operator new [], remember that all you are doing is allocating a large native memory-you cannot do anything for objects that do not exist in the array. In fact, you cannot even determine how many objects the array will have.FirstYou don't know how big each object is. After all, it is very likely that the base class operator new [] is called by inheritance to allocate memory to the array of derived class objects. The derived class objects are usually larger than the base class objects. Therefore, you cannot assume that the size of the object in the Base: operator new [] is sizeof (Base ), this means that you cannot assume that the number of objects in the array is (the number of bytes requested)/sizeof (Base ).Second, The parameter size_t passed to operator new [] may be more memory than the input object, because, as explained in Item 16, the dynamically allocated array may contain additional space to store the number of array elements.

 

2. Define operator delete conventions

 

There are so many conventions to be followed when operator new is implemented. Operator delete is easier to use. All you need to remember isC ++ always ensures that the delete null pointer is safe.So you need to follow this rule. The following is the pseudo code that implements non-member operator delete:

1 void operator delete(void *rawMemory) throw()2 {3 if (rawMemory == 0) return; // do nothing if the null4 // pointer is being deleted5 deallocate the memory pointed to by rawMemory;6 }

 

The member function version of this function is also simple, but you need to check the size of the object being deleted. Assume that your operator new of the class forwards the request to the Error Memory quantity to: operator new. You must also forward the delete request to the "error size :: operator delete:

 1 class Base { // same as before, but now 2 public: // operator delete is declared 3 static void* operator new(std::size_t size) throw(std::bad_alloc); 4 static void operator delete(void *rawMemory, std::size_t size) throw(); 5 ... 6 }; 7 void Base::operator delete(void *rawMemory, std::size_t size) throw() 8 { 9 10 if (rawMemory == 0) return; // check for null pointer11 12 if (size != sizeof(Base)) { // if size is “wrong,”13 14 15 ::operator delete(rawMemory); // have standard operator16 17 return;                                                                           // delete handle the request18 19 }                                                                                    20 21 deallocate the memory pointed to by rawMemory;      22 23 return;                                                                          24 25 }        

 

Interestingly, if the object to be deleted is derived from a base class without a virtual destructor, The size_t value passed to operator delete may be incorrect. This gives enough reason to declare the destructor in your base class as a virtual function, but Item 7 describes the second possible cause. Note that if you ignore the virtual destructor in the base class, the operations of the operator delete function may be incorrect.

 

3. Summary
  • Operator new should contain an infinite loop to try to allocate memory. If it cannot meet the requirements for memory, it should call new-handler and process requests of 0 bytes. The specific version of the class should process requests with larger memory blocks than expected.
  • If the pointer passed in operator delete is null, nothing should be done. A specific version of the class needs to process memory blocks larger than expected.

Related Article

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.