Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Memory allocation and constructor

I am sorry if it has been asked before explicitly stated in the standard, but I fail to find whether the memory for objects with automatic storage is allocated in the beginning of enclosing block or immediately before executing the constructor?

I am asking this because https://en.cppreference.com/w/cpp/language/storage_duration says that.

Storage duration All objects in a program have one of the following storage durations:

automatic storage duration. The storage for the object is allocated at the beginning of the enclosing code block and deallocated at the end. All local objects have this storage duration, except those declared static, extern or thread_local.

Now, does it mean that the storage space is allocated even where constructor is not invoked for some reason?

For example, I have something like that.

{
     if(somecondition1) throw something;
     MyHugeObject o{};
     /// do something
}

So, there a chance that MyHugeObject does not need to be constructed, yet according to the source I've cited, the memory for it is still allocated, despite the fact that the object might never get constructed. Is it the case or it is something implementation based?

like image 650
Raziel Magius Avatar asked Dec 31 '22 03:12

Raziel Magius


1 Answers

First of all, from a language standard perspective, you cannot access the object's storage outside of the lifetime of the object. Before the object is created, you do not know where the object is located, and after it has been destructed, accessing the storage yields undefined behavior. In short: A conforming C++ program cannot observe the difference of when the storage is allocated.

Automatic storage typically means "on the call-stack". I.e. allocation happens by decrementing the stack pointer, and deallocation happens be re-incrementing it. A compiler could emit code that does the stack pointer adjustments exactly where the lifetime of the object starts/ends, but this is inefficient: It would clutter the generated code with two extra instructions for each object that is used. This is especially a problem with objects that are created in a loop: The stack pointer would jump back and forth between two or more positions constantly.

To improve efficiency, compilers huddle all possible object allocations together into a single stack frame allocation: The compiler assigns an offset to each variable within the function, determines the max. size that is required to store all the variables that are present within the function, and allocates all the memory with a single stack pointer decrement instruction at the start of the function execution. Cleanup is then the respective stack pointer increment. This removes any allocation/deallocation overhead from loops as the variables in the next iteration will simply reuse the same spot within the stack frame as the previous iteration used. This is an important optimization, for many loops declare at least one variable.

The C++ standard does not care. Since use of the storage outside of an object's lifetime is UB, the compiler is free to do with the storage whatever it pleases to do. Programmers should not care as well, but they do tend to care about their programs execution times. And that's what most compilers optimize for by using stack frame allocation.

like image 139
cmaster - reinstate monica Avatar answered Jan 12 '23 00:01

cmaster - reinstate monica