lcs
lcs

Reputation: 4245

Conditional Stack Variables

Given the following function, will each of the local variables be declared on the stack?

std::string reallyCoolFunction(unsigned int a)
{
   if( a < 20 ) 
   {
     std::string result1 = "This function is really cool";
     return result1;
   }

   if( a >=20 && a <= 40 )
   {
     std::string result2 = "This function is kind of cool";
     return result2;
   }

   if( a > 40 )
   {
     std::string result3 = "This function is moderately cool";
     return result3;
   }

 std::string result4 = "This function really isn't that cool"; 
 return result4; // remove warning

}

In this situation, only one std::string is actually required, do all 4 get allocated on the stack, or does only 1 get allocated?

Upvotes: 15

Views: 805

Answers (6)

Matthieu M.
Matthieu M.

Reputation: 300209

Most probably 0 or maybe 1 (in Release) and certainly 4 (in Debug).

This is called the RVO: Return Value Optimization.

The compiler is actually allowed to elide the copy entirely and build the std::string directly in the slot provided by the caller. This is ABI specific, and as all optimizations only applies if a number of criteria are met; in your case it's probable that it will apply.

If you want to check, you can try to peruse the output of the compiler at various stages of its translation/optimization pipeline; it might be hard though depending on your toolchain.

Upvotes: 6

Mats Petersson
Mats Petersson

Reputation: 129504

The compiler is allowed to create 4, 1, 2 or 3 variables in this case. But most compilers that I'm aware of would create only one, or perhaps two, since the result4 is within the entire scope of the function.

Of course, if you do the "right" things the compiler may well get confused and do more than it absolutely needs to, so relying on this in critical functionality wouldn't be a particularly good thing.

Edit: I should add that the constructor for the std::string should only be run if the object is actually "used", so you may get the stack-space used, but it should not call the constructor. This is important if you do something like this:

void func()
{
    if (something)
    {
        Lock myLock(&global_lock_object);   // Constructor locks global_lock_object
        ... do stuff that needs global_lock_object locked ... 
        // end of scope runs destructor of Lock that unlocks global_lock_object. 
    }
    ... more code that takes a long time to execute but doesn't need lock. ...
}

Now, if the constructor for Lock was executed "too early", and destructed in the same scope [and it should be symmetrical], the lock would be held for the entire duration of the function, which would be wrong.

Upvotes: 0

Arne Mertz
Arne Mertz

Reputation: 24626

Short answer: look at the assembler.

Long answer: The compiler may apply static checks to determine if he needs all 4 or just some of the variables. Some compilers might allocate 4 different variables in debug mode, some might not. In Release mode, some optimizers might see that the first 3 are each in their own scope and thus can be put in the same place. Those compilers could therefore reserve space for two string variables on the stack. It needs just a bit more analysis to see that the fourth variable in no case coexists with the first three, so some optimizers might put the remainig two variables in the same place as well.

But whether your compiler does that, and whether he still does that in a just slightly more complicated situation, can only be determined for sure if you analyze the ouput.

Upvotes: 0

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726939

The decision is up to the compiler: since the automatic variables go out of scope before the next one comes in scope, the compiler can re-use their memory. Keep in mind that "stack" variables are actually variables with automatic storage duration according to the C++ specification, so they may not be on the stack at all.

Upvotes: 14

Alok Save
Alok Save

Reputation: 206606

Depends on the compiler.
If the compiler is intelligent enough to determine conclusively that only one string is needed it will emit code only for one string.

Is your compiler intelligent enough?

Easiest way is to check the the generated assembly code.

Do all 4 get allocated on the stack, or does only 1 get allocated?

Be it 1 or 4 strings, the string object is located on the stack local to the function but the memory for the string is allocated in freestore.

Upvotes: 2

Ivaylo Strandjev
Ivaylo Strandjev

Reputation: 71009

On most compilers only one string will be allocated. Keep in mind though std::string uses dynamic memory so most of its content will still be allocated on the heap.

Upvotes: 10

Related Questions