I imagine there's an answer to this somewhere, but I couldn't find it because there are lots of threading questions, and mine's pretty simple by comparison.
I'm not trying to make a threadsafe copy or assignment constructor or anything like that.
What I'm wondering, is if I have a class that represents a mutex lock and I return from a function that instantiates it, which happens first, the destructor of my mutex (thus unlocking it) or the copy constructor of the return value. Here's my example:
string blah::get_data(void)
{
MutexLock ml(shared_somewhere_else); // so this locks two threads from calling get_data at the same time
string x = "return data";
return x;
}
Somewhere else, we call get_data...
string result = get_data();
Thinking back to C for a second, you never return a pointer to a global variable, because the local variable goes out of scope after you return.
C++ doesn't have this problem because x will get copied into result. What I'm wondering is when that happens. Will my lock free before the copy is made?
In this simple example "return data" is static information, but what I'm working with, it's data that can be changed by another thread (also locked on the same MutexLock) so if the lock frees before the copy-to-result is made, the copy could get corrupted.
I'm not sure I'm explaining the question well, so I'll try to clarify if this doesn't make sense.
What's the order that local objects are destructed? ¶ Δ In reverse order of construction: First constructed, last destructed.
However, in your current implementation you're actually returning a shallow copy of NodeContainer. Once your copy goes out of scope its destructor is called, which deallocates its memory, which in this case is the original memory of your member, effectively making your member invalid.
Objects are always destroyed in reverse order of their creation. The reason for reverse order is, an object created later may use the previously created object.
A destructor takes no arguments and has no return type.
For previous standards (here I will use C++ 03), the closest the standard comes to declaring the sequence of operations in a return is from 6.6
6.6 Jump statements
- On exit from a scope (however accomplished), destructors (12.4) are called for all constructed objects with automatic storage duration (3.7.2) (named objects or temporaries) that are declared in that scope, in the reverse order of their declaration. Transfer out of a loop, out of a block, or back past an initialized variable with automatic storage duration involves the destruction of variables with automatic storage duration that are in scope at the point transferred from...
The return statement must complete in order to exit the [function] scope, implying that the copy-initialization must also complete. This order is not explicit. Various other quotes from 3.7.2 and 12.8 concisely state the same as above without providing explicit order. Working revisions (after Nov. 2014) include the quote below to address that. The defect report clarifies the change.
From the current working draft (N4527) of the standard as seen on the date of this question
6.6.3 The Return Statement
- The copy-initialization of the returned entity is sequenced before the destruction of temporaries at the end of the full-expression established by the operand of the return statement, which, in turn, is sequenced before the destruction of local variables (6.6) of the block enclosing the return statement.
Notice that this quote refers directly to 6.6. So I think it is safe to assume that the Mutex object will always be destroyed after the return expression has copy-initialized the return value.
While I am no standard guru, it seems quite obvious that destructors should be called after the copy is made - otherwise the very object you are copying would be destroyed before it is copied... :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With