Question:
I am starting in the world of programming, and some time ago I learned the use of dynamic memory, I learned it by heart and let it pass without understanding much of its essence and why it is used.
I know the basics: memory is allocated at runtime, it's the programmer's job to free it, it works with pointers, etc…
The thing is that at the moment I don't see the use of it. They always give me the same example in which a vector is created, the user is asked for its size and memory is allocated… But doesn't this generate the same problems as static memory? What's more, it seems to me a horrible example, because I could do the following:
int size;
cout<<"Introduzca tamano"<<size;
int vector[size];
and I would be doing a kind of rather crappy dynamic memory (according to my current knowledge), I would like you to give me an example where you really get the most out of "new" and "delete". Well, until now I only use dynamic memory in case I want to create a variable that I know I am going to delete later (temporary variable).
Answer:
…and it would be doing a kind of dynamic memory…
That functionality has a name: VLA (Variable Length Array). As you say, it is a kind of dynamic memory… with 3 slight drawbacks:
-
It is not part of the language specification.
It is an extension offered by many (if not all) compilers, which allows you to create arrays with an unknown size at compile time: they let you use a variable to indicate the size, when the language clearly indicates that a value should be used literal or, at most, the result of a
constexpr
function.int size; cout<<"Introduzca tamano"<<size; int vector[size];
warning: ISO C++ forbids variable length array 'vector'
-
The memory allocated in this way is freed automatically when you exit the function in which you allocate it. Any attempt to return a pointer to that memory area is undefined behavior . You can use it as an argument to other functions, but you can never use that memory area as a return value.
char *reserva( size_t size ) { char buff[size]; return buff; }
If you try to use the return value of that function, you will end up mashing up data that has been placed there by other functions.
-
It uses stack space , an area of memory dedicated to the storage of variables and data with a limited time to live… and an equally limited size . This size is set by the Operating System (or by windows, if the machine in question does not have an OS).
void algo( ) { char unaBurrada[std::numeric_limits< size_t >::max( )] = { 0 }; *unaBurrada = '\n'; }
That maximum size, and what happens if you exceed it, is up to the OS Some may expand that memory area automatically (up to a certain limit). Others assign the size when starting the program and don't touch it anymore. It is even possible that you are working without an OS, so there is no stack management and you will be limited to the characteristics of the hardware you are working on.
As you can see, using VLA is not a very good idea, beyond certain specific uses. You should use dynamic memory ( new
/ delete
) whenever:
- You need to use that memory area from more than one function.
- The allocated memory has a long or unknown life expectancy .
- The size of the block to use is greater than a certain limit (this depends on the OS). Personally, I usually set my limit to 4K (4096 bytes). It's an arbitrary number as good as any other 🙂
On the other hand, dynamic memory is not a panacea. Its use also depends on the OS and it also has certain drawbacks, which we can summarize in just 1:
- Is slow.
Dynamic memory management is not trivial. It is a wide topic, which presents several serious problems and that each OS / Compiler has solved in one way or another:
-
Fragmentation.
Memory is used in discrete-sized chunks . This carries the risk that the requested chunk is larger than the largest available chunk … even though the sum of available chunks is greater than the required size.
-
Synchronization between threads.
When your application has multiple threads, any one of them can request memory at any time. Memory management has to support this circumstance, so it usually uses blocking mechanisms (they stop all memory requests except the one that is being processed at a given moment).
As you can see, the topic of memory management is enough to write more than 1 book, and there is no general and universal method to use as a guide. Your application will have its own needs, which will not be the same as another's.