Cpp Chapter 9: Memory Models and Namespaces Part3
9.2.10 Storage schemes and dynamic allocation
Memory allocated by new operator is called dynamic memory. Dynamic memory is controlled by new and delete operators rather than scope and linkage rules.
Typically, the compiler has three separate memory chunks: one for static variables, one for automatic variables, one for dynamic storage.
Suppose you write this:
float * p_fees = new float [20];
the p_fees pointer still follows the rules of scope and linkage, so you pass the address to another function when using it.
Memory allocated by new typically is freed when the program terminates. However, the best practice is to use delete to free the memory allocated by new.
Initialization with the new operator
in C++11,for built-in types of C++ such as int and double, you use parentheses or braces enclosing the initialization value after the definition:
int * pi = new int (6);
double * pd = new double {99.99};
However, for structure or array, only braces are allowed:
struct where {double x; double y; double z;};
where * one = new where {2.5, 5.3, 7.2};
int * ar = new int [4] {2,4,6,7};
For classes with suitable constructors, use parentheses(discussed later).
When new fails
When new can't find the requested amount of memory, it throws a std::bad_alloc exception.(discussed later)
new: Operators, functions, and replacement functions
new and delete operator call upon two functions:
void * operator new(std::size_t);
void * operator new[](std::size_t);
void operator delete(void *)
void operator delete[](void *);
std::size_t is a typedef for some suitable integer type.(?) The functions above are collectivly termed allocation functions.
The placement new operator
Placement new operator allows you to specify the location to be used. Remember to include header file new when using placement new operator. An example of simple use of placement new operator:
#include <new>
struct chaff
{
char dross[20];
int slag;
};
char buffer1[50];
char buffer2[500];
int main()
{
chaff * p1, *p2;
int *p3, *p4;
p1 = new chaff;
p3 = new int[20];
p2 = new (buffer1) chaff; // allocate p2's content in buffer1
p4 = new (buffer2) int[20]; // allocate p4's content in buffer2
}
This code fragment shows the usage of placement new operator. p2 = new (place_supposed) thing; In the example, place_supposed could be an array. An example below:
// newplace.cpp -- using placement new
#include <iostream>
#include <new>
const int BUF = 512;
const int N = 5;
char buffer[BUF];
int main()
{
using namespace std;
double *pd1, *pd2;
int i;
cout << "Calling new and placement new:\n";
pd1 = new double[N];
pd2 = new (buffer) double[N]; // 111111111111111
for (i = 0; i < N; i++)
pd2[i] = pd1[i] = 1000 + 20.0 * i;
cout << "Memory addresses:\n" << " heap: " << pd1 << " static: " << (void *) buffer << endl;
cout << "Memory contents:\n";
for (i = 0; i < N; i++)
{
cout << pd1[i] << " at " << &pd1[i] << "; ";
cout << pd2[i] << " at " << &pd2[i] << endl;
}
cout << "\nCalling new and placement new a second time:\n";
double *pd3, *pd4;
pd3 = new double[N];
pd4 = new (buffer) double[N]; // 2222222222222
for (i = 0; i < N; i++)
pd4[i] = pd3[i] = 1000 + 40.0 * i;
cout << "Memory contents:\n";
for (int i = 0; i < N; i++)
{
cout << pd3[i] << " at " << &pd3[i] << "; ";
cout << pd4[i] << " at " << &pd4[i] << endl;
}
cout << "\nCalling new and placement new a third time:\n";
delete [] pd1;
pd1 = new double[N];
pd2 = new (buffer + N * sizeof(double)) double[N]; // 3333333333
for (i = 0; i < N; i++)
pd2[i] = pd1[i] = 1000 + 60 * i;
cout << "Memory contents:\n";
for (i = 0; i < N; i++)
{
cout << pd1[i] << " at " << &pd1[i] << "; ";
cout << pd2[i] << " at " << &pd2[i] << endl;
}
delete [] pd1;
delete [] pd3;
return 0;
}
This example illustrates 3 facts:
- Placement new indeed places the array in the buffer
- Placement new simply use the address passed to it. So it might overwrite past data(shown in the code with 11111111 and 2222222222). This feature is also illustrated that in code with 333333333, it uses a new chunk of memory instead of overwriting the previous, due to the fact that address "buffer + N * sizeof(double)" is passed to the placement new.
- When you delete a memory allocated by regular new, next new operator will reuse the memory. And, you can't apply delete to replacement new because the memory used by replacement new is predefined, which in this case is buffer, which is undeletable. Applying delete to replacement new will cause runtime error.
Noteworthy is that using delete to regular new will free the entire block