25

In C++ is a return value guaranteed to be created before automatic variables in the function are destroyed? Notice Basket::get:

class Basket
{
public:
  // Gift is a struct containing safely copyable things like int or string
  Gift gift;
  // Used to protect access and changes to gift
  Mutex mutex;

  // Copy gift into present, while locked to be thread safe
  void put (const Gift & gift)
  {
    Lock lock(mutex);   // Constructor locks, destructor unlocks mutex
    this->gift = gift;  // Gift assignment operator
  }

  // Return a memberwise-copy of gift, tries to be thread safe (but is it?)
  Gift get ()
  {
    Lock lock(mutex);  // Constructor locks, destructor unlocks mutex
    return gift;       // Gift copy constructor
  }
};

I need Basket::get to perform its Gift copy constructor (of the temp object returned) prior to destruction of the lock object. Otherwise the gift object being returned can be corrupted by a simultaneous call to put.

My tests show the gift copy is indeed created before lock destruction, however, is it guaranteed? If not, I'll need to create a second temporary inside the function, such as:

  Gift get ()
  {
    Gift result;
    {
      Lock lock(mutex);
      result = gift;
    }
    return result;
  }
maxpolk
  • 2,167
  • 1
  • 18
  • 24

2 Answers2

20

Yes, the auto variable will remain in scope until after the return is finished. This is especially true if you are using a compiler that optimizes the return, eg:

Gift get() 
{ 
    Lock lock(mutex);
    return gift;
} 

Gift g = basket.get();

Which would be equivilent to this sequence:

Gift g;
Lock lock(mutex);
g = Gift(gift);
lock.~Lock();

May be optimized to act more like this:

void get(Gift &ret) 
{ 
    Lock lock(mutex);
    ret = gift;
} 

Gift g;
basket.get(g);

Which would be equivilent to this sequence:

Gift g;
Lock lock(mutex);
g = gift;
lock.~Lock();

In other words, a temporary can be removed during the return.

JFMR
  • 23,265
  • 4
  • 52
  • 76
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • This is exactly the answer I needed re: a scenario of a mutex lock being destroyed after returning an rvalue. Thanks. – Dana M Apr 01 '20 at 23:42
  • So it's not guaranteed if this feature is contingent on the compiler optimising the return value. Why assume that the compiler will optimise? It's not safe to assume compiler optimisation. –  Jun 12 '20 at 06:35
6

It's guaranteed. The return value is copied (if necessary) before the destruction occurs. Here's a similar question / answer that gives a good description of the sequence.

Scope and return values in C++

Community
  • 1
  • 1
scotinus
  • 176
  • 5
  • 1
    There is no such thing as registers in the C++ standard. (Well, there is the `register` keyword, but that lost its meaning a long time ago.) Also, most objects wouldn't fit into a single register, anyway. – fredoverflow Dec 08 '11 at 21:29
  • If a local object was being returned, then sure, it would have to be copied before it was destroyed. However, this is something else. I have a data member of the class being returned, so the semantics of exactly when the copy occurs seems different. – maxpolk Dec 08 '11 at 21:31
  • @maxpolk You are returning the member by value. There will be a copy unless the compiler can optimize it to a reference assignment as Remy showed. If you were returning a reference or pointer the lock would still be destroyed after. – AJG85 Dec 08 '11 at 21:36
  • @FredOverflow - all true. I was thinking in assembly but even then my words were loose. Main point I wanted to make was that copy will occur before stack is unwound. Although has been stated, that too could be qualified by "if necessary". I'll edit the answer. – scotinus Dec 08 '11 at 22:16