You get a bonus - 1 coin for daily activity. Now you have 1 coin

3.6. Overload operation new

Lecture



3.6.1.Syntax

The default operation new can come in two forms:

1) new type <initializing expression>

2) new type [];

The first form is not used for arrays, the second for arrays.

The overloaded operation new can be defined in the following forms, respectively for non-arrays and for arrays:

void * operator new (size_t t [, remaining arguments]);

void * operator new [] (size_t t [, other arguments]);

The first and only required argument t must always be of type size_t. If the argument is of type size_t, then the function-function new is automatically substituted with the argument sizeof (t), i.e. it gets a value equal to the size of the object t in bytes.

For example, let the following function be given:

void * operator new (size_t t, int n) {return new char [t * n];}

and it is called as follows:

double * d = new (5) double;

Here t = double, n = 5.

As a result, after the call, the value of t in the function body will be equal to sizeof (double).

When overloading a new operation, several global new operations appear, one of which is defined in the default language itself, while others are overloaded. The question arises: how to distinguish between such operations? This is done by changing the number and types of their arguments. If only the types of arguments are changed, ambiguity may arise, which is a consequence of possible conversions of these types to each other. If such an ambiguity occurs, when accessing new, specify the type explicitly, for example:

new ((double) 5) double;

One of the reasons why the new operation is overloaded is in the desire to give it additional semantics, for example, the provision of diagnostic information or fault tolerance. In addition, a class can provide a more efficient memory allocation scheme than the system provides.

In accordance with the C ++ standard, the following new function functions are defined in the <new> header file, which allow passing, along with the required first size_t argument, to others.

void * operatop new (size_t t) throw (bad_alloc);

void * operatop new (size_t t, void * p) throw ();

void * operatop new (size_t t, const nothrow &) throw ();

void * operatop new (size_t t, allocator & a);

void * operatop new [] (size_t t) throw (bad_alloc);

void * operatop new [] (size_t t, void * p) throw ();

void * operatop new [] (size_t t, const nothrow &) throw ();

These functions use exception generation (throw) and its own memory allocator (allocator).

The version with nothrow allocates memory as usual, but if the allocation fails, 0 is returned, and no bad_alloc is generated. This allows us to use an error handling strategy before allocating an exception to allocate memory.

3.6.2. Rules for using the new operation

1. Objects organized with new have an unlimited lifetime. Therefore, the memory must be freed by the operator delete.

2. If memory is reserved for an array, the new operation returns a pointer to the first element of the array.

3. When reserving memory for an array, all dimensions must be expressed as positive values.

4. Arrays cannot be initialized.

5. Class objects can be organized using the new operation if the class has a default constructor.

6. Links cannot be organized using the new operation, since no memory is allocated for them.

The new operation itself calculates the memory requirement for the data type being organized, so the first operation parameter is always of type size_t.

3.6.3. Error handling operations new

Error handling of the new operation occurs in two stages:

1. It is established which functions are provided for error handling. Own functions must be of the type new_handler and are created using the set_new_handler function . The file new.h declared

typedef void (* new_handler) ();

new_handler set_new_handler (new_handler new_p);

2. The corresponding new_handler function is called. This feature should:

-or cause a bad_alloc exception;

-or to finish the program;

-or free the memory and try to allocate it again.

The diagnostic class bad_alloc is declared in new.h.

In the implementation of VS ++, a special global variable _new_handler is included , the value of which is a pointer to the new_handler function, which is executed when new fails. By default, if the new operation cannot allocate the required amount of memory, a bad_alloc exception is thrown. Initially, this exception was called xalloc and was defined in the except.h file. The xalloc exception continues to be used in many compilers. However, it is supplanted by the name bad_alloc defined in the C ++ standard.

Consider a few examples.

Example 3.6.1

In the example, using the try ... catch block allows you to control an unsuccessful attempt to allocate memory.

#include <iostream>

#include <new>

void main ()

{double * p;

try {

p = new double [1000];

cout << "Memory allocated successfully" << endl;

}

catch (bad_alloc xa)

{cout << "Memory allocation error \ n";

cout << xa.what (); return;}}

Example 3.6.2

Since in the previous example, under normal conditions, a memory allocation error is unlikely, in this example, a memory allocation error is enforced. The process of allocating memory lasts until an error occurs.

#include <iostream>

#include <new>

void main ()

{double * p;

do {

try {

p = new double [1000];

// cout << "Memory allocated successfully" << endl;

}

catch (bad_alloc xa)

{cout << "Memory allocation error \ n";

cout << xa.what ();

return;}

} while (p);

}

Example 3.6.3

The overloaded form of the operation new-operation new (nothow) is demonstrated.

#include <iostream>

#include <new>

void main ()

{double * p;

struct nothrow noth_ob;

do {

p = new (noth_ob) double [1000];

if (! p) cout << "Memory allocation error \ n";

else cout << "Memory allocated successfully \ n";

} while (p);

}

Example 3.6.4

Various forms of overloading the new operation are demonstrated .

#include <iostream.h>

#include <new.h>

double * p, * q, ** pp;

class demo

{int value;

public:

demo () {value = 0;}

demo (int i) {value = 1;}

void * operator new (size_t t, int, int);

void * operator new (size_t t, int);

void * operator new (size_t t, char *);

};

void * demo :: operator new (size_t t, int i, int j)

{

if (j) return new (i) demo;

else return NULL;

}

void * demo :: operator new (size_t t, int i)

{demo * p = :: new demo;

(* p) .value = i;

return p;

}

void * demo :: operator new (size_t t, char * z)

{

return :: new (z) demo;

}

void main ()

{class demo * p_ob1, * p_ob2;

// struct nothrow noth_ob;

p = new double;

pp = new double *;

p = new double (1.2); //initialization

q = new double [3]; // array

p_ob1 = new demo [10]; // array of demo objects

void (** f_ptr) (int); // pointer to pointer to function

f_ptr = new (void (* [3]) (int)); // array of function pointers

char z [sizeof (demo)]; // memory is reserved according to the value of // demo

p_ob2 = new (z) demo; // organizes a demo object in the memory area // which is indicated by the variable z

p_ob2 = new (3) demo; // demo-object with initialization

p_ob1 = new (3,0) demo; // returns a NULL pointer

// p_ob2 = new (noth_ob) demo [5]; // array of demo objects,

// returns an error if null

}


Comments


To leave a comment
If you have any suggestion, idea, thanks or comment, feel free to write. We really value feedback and are glad to hear your opinion.
To reply

C ++ (C plus plus)

Terms: C ++ (C plus plus)