Dynamic vs Static memory allocation
There is a structure:
typedef struct Point
{
int x;
int y;
} point_t;
What is the best way to create an" instance " of the structure?
-
Way:
point_t p;
-
Way:
point_t* p = new point_t();
The 1 way is preferable because of the speed, but not infrequently I see the 2 way. So what's the difference (other than being able to do delete
whenever you want)?
1 answers
The difference is in the way the data is stored.
In the first case, the variables are stored in the stack of the program. It follows from this:
Limited scope and lifetime.
When you exit the scope, the stored variables are automatically destroyed.
Faster memory allocation/deallocation speed.
In the second case, the variables are stored in theheap . Heap slower stack allocates and frees resources, does not automatically clean up (at least in standard C++), is prone to fragmentation. However, it has some special features:
The lifetime of a variable is not limited by the execution process. Without an explicit call to
delete
, the variable will exist until the end of the program execution.Knowing the address of a variable in the heap, it can be accessed from any scope.
A heap in a sense "rubber". Unlike the stack, it is only physically limited.
As a result, creating on the stack should be used in cases where the variable is small or of acceptable size, or is used only here and nowhere else.
If a variable is to be used during the life of the entire program, access to it is needed at any time, its creation / copying takes a lot of time/memory, or it is not known in advance how much memory is needed, that is it makes more sense to use a heap (create once and then use a ready-made instance from the heap, rather than create and initialize an analog in the stack each time).
However, when working with a heap, you need to be careful. Errors when working with dynamic memory are fraught with memory leaks and sigsegv-s.
I advise you to read more about the representation of the heap and stack. There are links to useful information.
UPD: Regarding the speed of working with the heap, I bring the exhaust disassembler of Qt 5.13 (MinGW 7.3.0):
3 [1] {
0x401560 55 push %rbp
0x401561 <+ 1> 48 89 e5 mov %rsp,%rbp
0x401564 <+ 4> 48 83 ec 30 sub $0x30,%rsp
0x401568 <+ 8> e8 f3 00 00 00 callq 0x401660 <__main>
4 [1] int a = 10;
0x40156d <+ 13> c7 45 fc 0a 00 00 00 movl $0xa,-0x4(%rbp)
6 [1] int *b = new int{10};
0x401574 <+ 20> b9 04 00 00 00 mov $0x4,%ecx
0x401579 <+ 25> e8 22 00 00 00 callq 0x4015a0 <_Znwy>
0x40157e <+ 30> c7 00 0a 00 00 00 movl $0xa,(%rax)
0x401584 <+ 36> 48 89 45 f0 mov %rax,-0x10(%rbp)
7 [1] delete b;
0x401588 <+ 40> 48 8b 45 f0 mov -0x10(%rbp),%rax
0x40158c <+ 44> 48 89 c1 mov %rax,%rcx
0x40158f <+ 47> e8 14 00 00 00 callq 0x4015a8 <_ZdlPv>
9 [1] return 1;
0x401594 <+ 52> b8 01 00 00 00 mov $0x1,%eax
10 [1] }
0x401599 <+ 57> 48 83 c4 30 add $0x30,%rsp
0x40159d <+ 61> 5d pop %rbp
0x40159e <+ 62> c3 retq
You can see that when working with dynamic memory, there are additional instructions plus a procedure call. Plus, synchronization issues are added to the heap in multithreaded applications (this is of course quite a secondary point, but it also has a place to be)
P.S. if I forgot something, I will be grateful for the additions.