Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
CPlusPlusNotesForProfessionals.pdf
Скачиваний:
47
Добавлен:
20.05.2023
Размер:
5.11 Mб
Скачать

Chapter 115: Memory management

Section 115.1: Free Storage (Heap, Dynamic Allocation ...)

The term 'heap' is a general computing term meaning an area of memory from which portions can be allocated and deallocated independently of the memory provided by the stack.

In C++ the Standard refers to this area as the Free Store which is considered a more accurate term.

Areas of memory allocated from the Free Store may live longer than the original scope in which it was allocated. Data too large to be stored on the stack may also be allocated from the Free Store.

Raw memory can be allocated and deallocated by the new and delete keywords.

float *foo = nullptr;

{

*foo = new float; // Allocates memory for a float float bar; // Stack allocated

} // End lifetime of bar, while foo still alive

delete foo; // Deletes the memory for the float at pF, invalidating the pointer foo = nullptr; // Setting the pointer to nullptr after delete is often considered good practice

It's also possible to allocate fixed size arrays with new and delete, with a slightly di erent syntax. Array allocation is not compatible with non-array allocation, and mixing the two will lead to heap corruption. Allocating an array also allocates memory to track the size of the array for later deletion in an implementation-defined way.

//Allocates memory for an array of 256 ints int *foo = new int[256];

//Deletes an array of 256 ints at foo delete[] foo;

When using new and delete instead malloc and free, the constructor and destructor will get executed (Similar to stack based objects). This is why new and delete are preferred over malloc and free.

struct ComplexType { int a = 0;

ComplexType() { std::cout << "Ctor" << std::endl; } ~ComplexType() { std::cout << "Dtor" << std::endl; }

};

// Allocates memory for a ComplexType, and calls its constructor ComplexType *foo = new ComplexType();

//Calls the destructor for ComplexType() and deletes memory for a Complextype at pC delete foo;

Version ≥ C++11

From C++11 on, the use of smart pointers is recommended for indicating ownership.

Version ≥ C++14

C++14 added std::make_unique to the STL, changing the recommendation to favor std::make_unique or std::make_shared instead of using naked new and delete.

GoalKicker.com – C++ Notes for Professionals

578

Section 115.2: Placement new

There are situations when we don't want to rely upon Free Store for allocating memory and we want to use custom memory allocations using new.

For these situations we can use Placement New, where we can tell `new' operator to allocate memory from a preallocated memory location

For example

int a4byteInteger;

char *a4byteChar = new (&a4byteInteger) char[4];

In this example, the memory pointed by a4byteChar is 4 byte allocated to 'stack' via integer variable a4byteInteger.

The benefit of this kind of memory allocation is the fact that programmers control the allocation. In the example above, since a4byteInteger is allocated on stack, we don't need to make an explicit call to 'delete a4byteChar`.

Same behavior can be achieved for dynamic allocated memory also. For example

int *a8byteDynamicInteger = new int[2];

char *a8byteChar = new (a8byteDynamicInteger) char[8];

In this case, the memory pointer by a8byteChar will be referring to dynamic memory allocated by a8byteDynamicInteger. In this case however, we need to explicitly calldelete a8byteDynamicInteger to release the memory

Another example for C++ Class

struct ComplexType { int a;

ComplexType() : a(0) {} ~ComplexType() {}

};

int main() {

char* dynArray = new char[256];

//Calls ComplexType's constructor to initialize memory as a ComplexType new((void*)dynArray) ComplexType();

//Clean up memory once we're done reinterpret_cast<ComplexType*>(dynArray)->~ComplexType(); delete[] dynArray;

//Stack memory can also be used with placement new

alignas(ComplexType) char localArray[256]; //alignas() available since C++11

new((void*)localArray) ComplexType();

//Only need to call the destructor for stack memory reinterpret_cast<ComplexType*>(localArray)->~ComplexType();

return 0;

}

GoalKicker.com – C++ Notes for Professionals

579

Section 115.3: Stack

The stack is a small region of memory into which temporary values are placed during execution. Allocating data into the stack is very fast compared to heap allocation, as all the memory has already been assigned for this purpose.

int main() {

int a = 0; //Stored on the stack return a;

}

The stack is named because chains of function calls will have their temporary memory 'stacked' on top of each other, each one using a separate small section of memory.

float bar() {

//f will be placed on the stack after anything else float f = 2;

return f;

}

double foo() {

//d will be placed just after anything within main() double d = bar();

return d;

}

int main() {

//The stack has no user variables stored in it until foo() is called return (int)foo();

}

Data stored on the stack is only valid so long as the scope that allocated the variable is still active.

int* pA = nullptr;

void foo() { int b = *pA; pA = &b;

}

int main() { int a = 5; pA = &a; foo();

//Undefined behavior, the value pointed to by pA is no longer in scope a = *pA;

}

GoalKicker.com – C++ Notes for Professionals

580