Commit 0612492b authored by ROUVREAU Vincent's avatar ROUVREAU Vincent Committed by GILLES Sebastien
Browse files

typo

parent 5041da80
%% Cell type:markdown id: tags:
# [Getting started in C++](./) - [Procedural programming](./0-main.ipynb) - [Dynamic allocations](./5-DynamicAllocation.ipynb)
%% Cell type:markdown id: tags:
<h1>Table of contents<span class="tocSkip"></span></h1>
<div class="toc"><ul class="toc-item"><li><span><a href="#Introduction" data-toc-modified-id="Introduction-1">Introduction</a></span></li><li><span><a href="#Stack" data-toc-modified-id="Stack-2">Stack</a></span></li><li><span><a href="#Heap-and-free-store" data-toc-modified-id="Heap-and-free-store-3">Heap and free store</a></span><ul class="toc-item"><li><span><a href="#Free-store?" data-toc-modified-id="Free-store?-3.1">Free store?</a></span></li></ul></li><li><span><a href="#Arrays-on-heap" data-toc-modified-id="Arrays-on-heap-4">Arrays on heap</a></span></li></ul></div>
%% Cell type:markdown id: tags:
## Introduction
In C++, we can finely control the life cycle of objects and manage the memory allocated to them. This is what makes it possible to create more powerful applications than with many other languages, but it is also the main source of errors in the language. Pointers and dynamic memory management: watch out for danger!
## Stack
The ordinary variables of C++ have a lifetime limited to the current instruction block, whether it is the current function, or a instruction block attached to an `if`, `for` or just independant.
The ordinary variables of C++ have a lifetime limited to the current instruction block, whether it is the current function, or an instruction block attached to an `if`, `for` or just independant.
The memory allocated to them is located in an area called a **stack**, and is automatically relieved when exiting the current block using the **last in, first out** principle.
%% Cell type:code id: tags:
``` C++17
{
{
int a { 5 };
double b { 7.4 };
} // at the end of this block, b is released first and then a - but 99.99 % of the time you shouldn't care
// about that order!
// a and b are not available here
}
```
%% Cell type:markdown id: tags:
There are few limitations with the stack:
* The number of memory you can allocate on the stack is rather limited. On a current POSIX OS the order of magnitude is ~ 8 Mo (on Unix type `ulimit -a` in a terminal to get this information). If you allocate more you will get a **stack overflow** (and now you know why the [most popular developers forum](https://stackoverflow.com/) is named this way!)
* The information is very local; you can't use it elsewhere. If you pass the variable as argument in a function for instance a copy is made (or if you're using a reference or a pointer you have to be sure all is done when the block is exited!)
* Stack information must be known at compile time: if you're allocating an array on the stack you must know its size beforehand.
%% Cell type:markdown id: tags:
## Heap and free store
You can in fact also explicitly place a variable in another memory area called **heap** or **free store**; doing so overcomes the stack limitations mentioned above.
This is done by calling the `new` operator, which reserves the memory and returns its address, so that the user can store it _with a pointer_.
The **heap** is independent of the **stack** and the variable thus created exists as long as the `delete` operator is not explicitly called. The creation and destruction of this type of variable is the responsibility of the programmer.
%% Cell type:code id: tags:
``` C++17
#include <iostream>
{
int* n = new int(5); // variable created on the heap and initialized with value 5.
std::cout << *n << std::endl;
delete n; // deletion must be explicitly called; if not there is a memory leak!
}
```
%% Cell type:markdown id: tags:
What is especially tricky is that:
* Creating and destroying can be done in places very disconnected in your program.
* You must ensure that whatever the runtime path used in your program each variable allocated on the heap:
- is destroyed (otherwise you get a **memory leak**)
- is only destroyed once (or your program will likely crash with a message about **double deletion**).
In sophisticated programs, this could lead in serious and tedious bookkeeping to ensure all variables are properly handled, even if tools such as [Valgrind](http://www.valgrind.org/) or [Address sanitizer](https://github.com/google/sanitizers/wiki/AddressSanitizer) may help to find out those you will probably have forgotten somewhere along the way.
To be honest, C++ gets quite a bad name due to this tedious memory handling; fortunately the RAII idiom provides a neat way to automatize nicely memory management (which we'll study [later](../5-UsefulConceptsAndSTL/2-RAII.ipynb)) and some vocal critics on forums that regret the lack of [garbage collection](https://en.wikipedia.org/wiki/Garbage_collection_(computer_science)) might actually not be aware of this fundamental (from my point of view at least) idiom.
%% Cell type:markdown id: tags:
### Free store?
**Free store** is very similar in functionality to the **heap** (to the point I had to [check the difference](https://stackoverflow.com/questions/1350819/c-free-store-vs-heap) before writing this...) , and more often than not one word might be used as the other. If you want to be pedantic:
* When memory is handled by `new`/`delete`, you should talk about **free store**.
* When memory is handled by `malloc`/`free` (the C functions), you should talk about **heap**.
Pedantry aside, the important thing to know is to never mix both syntax: if you allocate memory by `new` don't use `free` to relieve it.
%% Cell type:markdown id: tags:
## Arrays on heap
If you want to init an array which size you do not know at compile time or that might overflow the stack, you may to do with `new` syntax mixed with `[]`:
%% Cell type:code id: tags:
``` C++17
{
const unsigned int Ndigit = 5; // not known at compile-time!
int* pi_first_five_digits = new int[Ndigit];
pi_first_five_digits[0] = 3;
pi_first_five_digits[1] = 1;
pi_first_five_digits[2] = 4;
pi_first_five_digits[3] = 1;
pi_first_five_digits[4] = 5;
delete[] pi_first_five_digits;
}
```
%% Cell type:markdown id: tags:
Please notice that:
* No value can be assigned in construction: you must first allocate the memory for the array and only in a second time fill it.
* A `[]` **must** be added to the **delete** instruction to indicate to the compiler this is actually an array that is destroyed.
In fact, my advice would be to avoid entirely to deal directly with such arrays and use containers from the standard library such as `std::vector`:
%% Cell type:code id: tags:
``` C++17
#include <vector>
{
std::vector<int> pi_first_five_digits { 3, 1, 4, 1, 5 };
}
```
%% Cell type:markdown id: tags:
that does the exact same job in a shorter way and is much more secure to use (spoiler: `std::vector` is built upon the RAII idiom mentioned briefly in this notebook).
We shall see `std::vector` more deeply [later](../5-UsefulConceptsAndSTL/3-Containers.ipynb) but will nonetheless use it before this as it is a rather elementary brick in most C++ codes.
%% Cell type:markdown id: tags:
© _CNRS 2016_ - _Inria 2018-2021_
_This notebook is an adaptation of a lecture prepared by David Chamont (CNRS) under the terms of the licence [Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)](http://creativecommons.org/licenses/by-nc-sa/4.0/)_
_The present version has been written by Sébastien Gilles and Vincent Rouvreau (Inria)_
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment