C ++ FAQ Lite [16] - Free Storage (FREESTORE) management (on)

zhaozj2021-02-08  281

[16] Free Storage (Part Of C FAQ Lite, Copyright? 1991-2001, Marshall Cline, Cline@parashift.com)

体,, nicrosoft @ sunistudio.com (East day production room, East day document)

FAQS in section [16]:

[16.1] DELETE P Delete Pointer P or delete the data pointed to by the pointer * p? [16.2] Can free () a pointer allocated by the NEW? Can DELETE a pointer assigned by malloc ()? [16.3] Why use New to replace the original trustworthy malloc ()? [16.4] Can I use Realloc () on a pointer allocated by the NEW? [16.5] Do you need to check NULL after p = new fred ()? [16.6] How do I confine my (ancient) compiler to automatically check if NEW returns NULL? [16.7] Do you need to check NULL before DELETE P? [16.8] Which two steps do DELETE P do? [16.9] In P = New Fred (), if the FRED constructor throws an exception, is it "leak"? [16.10] How to assign / release an array of objects? [16.11] If the delete is allocated by the New T [N], it is missed [] how will it? [16.12] When DELETE is a built-in type (CHAR, INT, etc.), can you remove []? [16.13] P = new fred [n], how do the compiler in delete [] P How do you know that N objects are destructed? [16.14] Does member functions call DELETE THIS? [16.15] How to assign multiple dimensional arrays with NEW? [16.16] But the previous FAQ code is too skill and it is easy to make an error, is there a simpler method? [16.17] But the Matrix class above is for Fred! Is there a way to universal? [16.18] Is there any other method to establish a Matrix template?

[16.1] DELETE P Delete Pointer P or delete the data pointed to by the pointer * P?

The data pointed to by the pointer.

The keyword should be delete_the_thing_pointed_to_by. The same situation also occurs in the memory of the release pointer in c: Free (p) is actually referring to Free_THE_STUFF_POINTED_TO_BY (P).

[TOP | BOTTOM | Previous Section | Next Section]

[16.2] Can you free () a pointer allocated by the NEW? Can DELETE a pointer assigned by malloc ()?

Do not!

Simultaneous use of malloc () and delete simultaneously in a program, using new and free () are reasonable legal. However, free () is called by the pointer assigned by the NEW, or the pointer assigned by malloc () is called delete, illegal, despicable.

Beware! I occasionally received some people's e-mail, they told me that they work normally on their machine X and the compiler y. But this doesn't make it true! Sometimes they say: "But I just use the character number". " Even if so, Malloc () and delete are mixed on the same pointer, or New and Free () are mixed on the same pointer. If allocated by P = New Char [n], you must use delete [] p; free (p) can not be used. If you assign p = malloc (n), you must use free (p); you can't use Delete [] P or Delete P! Mix them if you put the code on your new machine, or on your new compiler, or just the new version of the same compiler, you may cause trouble-time disasters failure. Remember this warning.

[TOP | BOTTOM | Previous Section | Next Section]

[16.3] Why use New to replace the original trustworthy malloc ()?

Constructs function / destructive functions, type security, overridability.

Constructor: Different Malloc (SIZEOF (FRED), New Fred () calls FRED constructor. Similarly, the delete p calls the destructor of * P. Type Safety: Malloc () Returns a void * without type of secure. NEW FRED () Returns a pointer to a correct type (a Fred *). Overparable: New is an operator that can be rewritten / overwritten, and malloc () is not overwritten on the class.

[TOP | BOTTOM | Previous Section | Next Section]

[16.4] Can I use Realloc () on a pointer allocated by the NEW?

Can't!

Realloc () When you copy, use the bitwise copy operator, which breaks many C objects. C objects should be allowed to copy them themselves. They use their own copy constructor or assignment operator.

In addition, the heap used by New is different from malloc () and realloc ()!

[TOP | BOTTOM | Previous Section | Next Section]

[16.5] Do you need to check NULL after p = new fred ()?

[Recently Changed So It Uses New-Style Headers and The Std :: Syntax (on 7/00). Click Here To Go To The Next FAQ in The "Chain" of Recent Changes .]

Do not! (But if you only have an old compiler, you may have to force the New operator to throw an exception when the memory overflows.)

Always write explicit NULL test after each New call is very painful. The following code is very monotonous:

Fred * p = new fred (); if (p == null) throw std :: bad_alloc ();

If your compiler does not support (or if you refuse to use) exception, your code may be more toned: fred * p = new fred (); if (p == null) {std :: cerr << "COULDN 'T Allocate Memory for A Fred "<< endl; Abort ();

Chest. In C , if the runtime system cannot assign a SIZEOF (FRED) byte memory for P = New Fred (), a std :: Bad_alloc exception is thrown. Different with malloc (), New will never return null!

So you just write:

Fred * p = new fred (); // does not need to check if P is NULL

However, if your compiler is very old, it may not support this. Check the documentation for your compiler to find "New". If you only have an old compiler, you must force the compiler to have this behavior.

[TOP | BOTTOM | Previous Section | Next Section]

[16.6] How do I confine my (ancient) compiler to automatically check if NEW returns NULL?

[Recently Changed The Example to Use Throw Rather Than Abort () THROW Stan Brown; Changed To Use New-Style Headers and the Std :: Syntax (on 7/00). Click Here To Go To The Next Faq in The "Chain "of serious change .

Eventually your compiler will support.

If you only have an ancient NULL test , you can install a "new handler" function to force the runtime system to test. Your "New Handler" function can do anything you want, such as throwing an exception, delete some objects and returns (in the case where Operator New is trying to allocate), print a message or from the program from the program from the program. and many more.

Here is an example of "new handler", it prints the message and throws an exception. It uses std :: set_new_handler () installed:

#include // Get std :: set_new_handler #include // Get abort () #include // get std :: cerr class alloc_error: public std :: exception {public: alloc_ERROR (): EXCEPTION () {}}; void mynewhandler () {// This is your own handler. It can do anything you want to do. Throw alloc_ERROR ();} int main () {std :: set_new_handler (mynewhandler); // Install your "new handler" // ...}

After std :: set_new_handler () is executed, if the memory is insufficient, the Operator New will call your MyNewHandler (). This means that NEW will not return null: fred * p = new fred (); // does not need to check if P is NULL

Note: If your compiler does not support exception processing, as the final appeal, you can change the throw ...; this line is changed to:

Std :: CERR << "Attempt to Allocate Memory Failed!" << std :: endl; abort ();

Note: If some globally / static object constructor uses new, because their constructor is called before the main () starts, it does not use the MyNewHandler () function. Unfortunately, there is no easy way to ensure that std :: set_new_handler () is called before the first use of New. For example, even if you put std :: set_new_handler () in the constructor of the global object, you still can't know that the module containing the global object ("Compile Unit" is first or in the end or in the middle of a location is explained. . So you still have not guaranteed that the call of std :: set_new_handler () is called before the constructor of any other global object.

[TOP | BOTTOM | Previous Section | Next Section]

[16.7] Do you need to check NULL before DELETE P?

No need!

C language guarantee, if P is equal to NULL, DELETE P does not make anything. Since it can be tested afterwards, and most test methods are forcibly testing each branch point, so you should not add extra IF test.

wrong:

IF (p! = null) delete P;

correct:

Delete P;

[TOP | BOTTOM | Previous Section | Next Section]

[16.8] Which two steps do DELETE P do?

Delete P is a two-step process: call the destructor, then release memory. The code generated by the delete P looks like this (assuming is a fred * type):

// Original code: delete p; if (p! = Null) {p-> ~ fred (); operator delete (p);}

P-> ~ FRED () statement calls the destructuring function of the Fred object pointing to.

The Operator Delete (P) statement calls the memory release primitive Void Operator Delete (Void * P). This primitive is similar to Free (Void * P). (However, it is noted that two cannot be interchanged; for example, there is no guarantee that these two memory release primitives will use the same pile!).

[TOP | BOTTOM | Previous Section | Next Section]

[16.9] In P = New Fred (), if the FRED constructor throws an exception, is it "leak"?

will not.

If an exception occurs in a Fred constructor in the P = New Fred (), the C language ensures that the allocated sizeOf (FRED) byte memory will automatically reclaim from the heap.

Here are two details: New fred () is a two-step process:

SIZEOF (FRED) byte memory uses VOID * OPERATOR New (size_t nbytes) primitives assigned. This primitive is similar to malloc (size_t nbytes). (However, pay attention, they can't interchange it; for example, no one is guaranteed to use the same pile!). It creates an object in memory by calling the Fred constructor. The first step is passed to the constructor as the THIS parameter. This step is wrapped in a block to handle the abnormality in this step. Therefore, the actual code may be like this:

// Original code: fred * p = new fred (); fred * p = (fred *) Operator new; try {new (p) fred (); // placement new } catch (...) {Operator delete (p); // Release memory throw; // Re-throw anomalous}

This statement labeled "Placement New" calls the FRED constructor. The pointer P has become a THIS pointer in which the function fred :: fred () interior.

[TOP | BOTTOM | Previous Section | Next Section]

[16.10] How to assign / release an array of objects?

Use P = New T [N] and Delete [] P:

Fred * p = new fred [100]; // ... delete [] p;

At any time, you allocate an array of objects through New (usually in the expression [N]), you must use in the delete statement []. This syntax is necessary, because there is no syntax that can distinguish between a pointer to an object and pointing to a pointer to an array of objects (some things blested from C).

[TOP | BOTTOM | Previous Section | Next Section]

[16.11] If the delete is allocated by the New T [N], it is missed [] how will it?

All life is devastated.

Correctly connect New t [n] and delete [] P is programmers - not compiler - responsibility. If you make a mistake, the compiler gives an error message when compiling or runtime. Heap (HEAP) is destroyed is possible, or worse, your program may die.

[TOP | BOTTOM | Previous Section | Next Section]

[16.12] When DELETE is a built-in type (CHAR, INT, etc.), can you remove []?

No!

Sometimes the programmer will think that in delete [] P exists [] just for the compiler to call the appropriate destructor for each element in the array. For this reason, they think that some built-in types, such as char or int, no need []. For example, they think the following is a legal code:

Void Usercode (int N) {char * p = new char [n]; // ... delete p; // <- wrong! It should be delete [] P! }

But the above code is wrong and will lead to a runtime disaster. In more detail, DELETE P call is Operator Delete (Void *), and Delete [] P calls Operator Delete [] (Void *). Although the latter's default behavior is called the former, it is allowed to replace the latter to replace it (in this case, the corresponding Operator New [] (SIZE_T) in this case will replace the NEW). If the replaced delete [] code is not compatible with the delete code, and that the error is called (for example, you wrote DELETE P instead of delete [] P), it may be done during runtime. [TOP | BOTTOM | Previous Section | Next Section]

[16.13] P = New fred [n], the compiler How does it know when there is an object in Delete [] P?

[Recently Changed "Popluar" to "Popular" THANKS TO FABRICE CLERC (on 7/00). Click Here To Go To The next FAQ in The "Chain" of Recent Changes .]

Streamline replies: magic.

Detailed Answer: The runtime system saves the number N of the object in a place that can be obtained by pointer P. There are two universal technologies to achieve. These technologies are used in commercial compilers, and they have weighed, it is not perfect. These techniques are:

The excess allocation array and places N on the left side of the first Fred object. Use the associated array, P as the key, n as the value.

[TOP | BOTTOM | Previous Section | Next Section]

[16.14] Does member functions call DELETE THIS?

As long as you are careful, an object requests to commit suicide. Yes.

The following is my definition of "Be careful":

You have to determine 100%, this object is allocated with new (NEW [], nor is it locked by NEW , nor a local object on a stack. It is not a global, nor is it a member of another object, but a general New). You have to determine 100%, the member function is the member function that the THIS object last call. You have to determine 100%, the remaining member functions (after DELETE THIS) does not come into contact with any one of the THIS object (including calling any other member functions or access any data). You have to determine 100%, no longer access the THIS pointer after Delete this. In other words, you can't check it, compare it and other pointers, compare it, print it, convert it, do anything to it.

Naturally, I have to habitually admonish this situation: When your pointer is a pointer to the base class, there is no false argument function (you can't delete this).

[TOP | BOTTOM | Previous Section | Next Section]

[16.15] How to assign multiple dimensional arrays with NEW?

[Recently Fixed a Leak in the third manipulateArray () by move block (on 7/00). Click Here to go to the next faq in the "chain" of recent changes . There are many ways depending on how much flexibility do you want to make arms. One extreme is that if you know all the dimensions of the array when you compile, you can static (just like in C):

Class Fred {/ *...*/}; void SomeFunction (Fred & Fred); void manipulateArray () {const unsigned nrows = 10; // row number is compiled period constant const unsigned ncols = 20; // Column number is compiled Meeting Fred Matrix [NROWS] [NCOLS]; for (unsigned i = 0; i

More general, the size of the matrix is ​​only known when running, but it is determined that it is a rectangle. In this case, you need to use the heap ("Free Storage") ("Free Storage") ("Free Storage"), but at least you can use all elements in the free memory block.

Void ManipulateArray (unsigned nROWS, Unsigned ncols) {fred * matrix = new fred [nROWS * ncols]; // Since we use simple pointers above, we need to be very // to carefully avoid leaking through the DELETE code. // This is why it is to capture all anomalies: try {// Access (i, j) element method: for (unsigned i = 0; i

Void ManipulateArray (unsigned nROWS, unsigned ncols []) {typedef fred * fredptr; // If you throw an exception, don't be a vulnerability: fredptr * matrix = new fredptr [nROWS]; // By preventing abnormalities later , Set each element to null: // (see a comment at the top of the TRY block.) For (unsigned i = 0; i 0; --i) delete [] Matrix [i-1]; delete [] matrix; return;} // ...} catch (...) {// Make sure you do delete: // pay attention to Matrix [...] when there is an abnormality Some pointers may be // null, but because delete null is legal, there is no problem. For (unsigned i = nrows; i> 0; --i) delete [] matrix [i-1]; delete [] matrix; throw; // Re-throwing the current exception} // Make sure DELETE is also done at the end of the function: // Note the release and allocation reverse: for (unsigned i = nrows; i> 0; --i) delete [] Matrix [i-1]; delete [] matrix;} pay attention to the release process MATRIX [i-1] usage of. This prevents the stepper of the unsigned value I of less than 0.

Finally, pay attention to pointers and arrays will bring trouble. Usually, it is best to package your pointer in a class with a secure and simple interface. The next FAQ tells you how to do this.

[TOP | BOTTOM | Previous Section | Next Section]

[16.16] But the previous FAQ code is too easy to make an error! Is there a simpler way?

[Recently clarified the last paragraph (on 7/00) and fixed the Star Trek movie number thanks to Chris Sheppard (on 4/01) and wordsmithed last paragraph at the suggestion of prapp (on 4/01). Click here to go to The Next FAQ in The "Chain" of Recent Changes .

The previous FAQ is too skillful and it is easy to errors because it uses a pointer, we know that the pointer and array will bring trouble. The solution is to encapsulate the pointer into a class with a secure and simple interface. For example, we can define a Matrix class to handle a rectangular matrix, the user code will be much more simpler than the code of the rectangular matrix in the previous FAQ:

// Matrix class code is displayed below ... Void SomeFunction (Fred & Fred); Void ManipulateArray (unsigned ncols) {Matrix Matrix (ncols); // Construct a Matrix for (unsigned i = 0; i

It is important to note that the code is short. For example, there is no DELETE statement in the above code, and there will be no memory leaks. This assumption is only based on the destructor correctly completes its work.

The following is the code that makes the above possible Matrix:

Class Matrix {public: Matrix (unsigned nROWS, UNSIGNED NCOLS); // If any one size is 0, throw an exception of the BadSize object: Class BadSize {}; // Based on a large third method (translation: ie, the three must Presented): ~ Matrix (); Matrix (const Matrix & m); Matrix & Operator = (const Matrix & m); // Access to (i, j) Element Access method: Fred & Operator () (unsigned i, unsigned J); Const Fred & operator () (unsigned i, unsigned j) const; // if i or j is too large, the object is thrown BoundsViolation class BoundsViolation {}; private: Fred * data_; unsigned nrows_, ncols_;}; inline Fred & Matrix :: operator () (Unsigned row, unsigned color {if (row> = nROWS_ || col> = ncols_) throw boundsviolation (); return data_ [rot * ncols_ col];} inline const fred & matrix :: Operator () (unsigned Row, unsigned col) const {if (row> = nrows_ || col> = ncols_) throw boundsviological (); returntric_ [r * ncols_ col];} matrix :: matrix (unsigned ncols): Data_ ( NEWS_ (NROWS), NCOLS_ (NCOLS) {IF (nROWS == 0 || ncols == 0) Throw Badsize (); Matrix :: ~ matrix () {delete [] Data_;} Note that the above Matrix class completes two things: move the skillful memory management code from the customer code (for example, main ()) to the class, and overall reduction Programming. This is important. For example, assume that Matrix is ​​slightly reusable, and the complexity is moved from Matrix's users [plural] to Matrix itself [singular] is equal to moving complexity from many aspects. Anyone who reads Star Tour 2 knows that most of the interests are above a few or individual interests.

[TOP | BOTTOM | Previous Section | Next Section]

[16.17] But the Matrix class above is for Fred! Is there a way to universal?

[Recently Rewrote (on 7/00). Click Here to Go To The Next FAQ in The "Chain" of Recent Changes .

Yes; that is to use the template:

How can I use a template:

#include "fred.hpp" // Get the definition of the Fred class // Matrix code is displayed later ... Void SomeFunction (Fred & Fred); Void ManipulateArray (unsigned nROWS, UNSIGNED NCOLS) {Matrix Matrix (NROWS, NCOLS); // Constructing a Matrix for (unsigned i = 0; i

It is now easy to use Matrix now. For example, the following is std :: string Using a Matrix (std :: string is a standard string class):

#include void Somefunction (std :: string & s); void manipulateArray (unsigned nRows, unsigned ncols) {matrix matrix (ncols); // Construct a Matrix For (unsigned i = 0; i

Therefore, you can get the full family of classes from the template. For example, Matrix , Matrix , Matrix > and more.

The following is a method of implementing this template:

Template // See Template Template Class Matrix {public: Matrix (unsigned nrows, unsigned ncols); // If you are 0, throw BadSize object class badsize {}; // Based on the big three Law (translation: i.e. , J) Element Access Method: T & Operator () (unsigned i, unsigned j); const t & operator () (unsigned i, unsigned j) const; // If i or j is too large, throw BoundsViolaion object class BoundsViolation {}; Private: t * data_; unsigned nrows_, ncols_;}; template Inline T & Matrix :: Operator () (unsigned row, unsigned color {if (row> = nrows_ || col> = NCOLS_) Throw Boundsviology (); return data_ [r * ncols_ col];} template inline const t & matrix :: operator () (unsigned row, unsigned col) const {if (row> = NROWS_ || col> = ncols_) Throw Boundsvilation (); return data_ [r * ncols_ col];} template Inline Matrix :: Matrix (unsigned ncols): DATA_ (New T NROWS * NCOLS]), NRO WS_ (NROWS), NCOLS_ (NCOLS) {if (nROWS == 0 | Ncols == 0) throw badsize ();} template inline matrix :: ~ matrix () {delete [] data_ } [TOP | BOTTOM | Previous section | Next Section]

[16.18] Is there any other method to establish a Matrix template?

[Recently Created Thanks to Jesper Rasmussen (on 4/01). Click Here to Go To The Next Faq in The "Chain" of Recent Changes .

Vector vector vector with standard Vector template.

The following code uses a vector > (note the space between the two> symbols).

#include Template // See Template Template Class Matrix {public: Matrix (unsigned nrows, unsigned ncols); // If any size is 0, throw Badsize object class bagsize {}; / / Don't need a big three law! // Get (i, j) Element Access Method: T & Operator () (unsigned i, unsigned J); const t & operator () (unsigned i, unsigned j) const; // If i or j is too large, then throw Boundsviolation object class boundsviolation {}; private: vector > data_;}; template Inline T & Matrix :: Operator () (unsigned row, unsigned color {if (row> = NROWS_ || col> = ncols_) Throw Boundsviolation (); return data_ [row] [col];} template Inline const t & matrix :: operator () (unsigned row, unsigned col) const {ix (Row> = nROWS_ || COL> = ncols_) throw boundsviolation (); return data_ [row] [col];} template Matrix :: Matrix (unsigned ncols): data_ (nrows) ) {If (nROWS == 0 || ncols == 0) Throw Badsize (); for (unsigned i = 0; i

E-mail the author [C FAQ Lite | Table of Contents | Subject Index | About The Author | | Download Your Own Copy] Revised Apr 8, 2001

转载请注明原文地址:https://www.9cbs.com/read-2056.html

New Post(0)