Order of destructor execution.

E

eshneto

Sorry if this may seem to be very obvious, but it is important and I
decided to ask.

I have the following classes:

class MutexWrapper
{
public:
MutexWrapper( void );
void lock( void ); //Maybe const, whatever.
void unlock( void ); //As well.
~MutexWrapper( void );
}

class MutexLocker
{
public:
MutexLocker( MutexWrapper& mut ){ mut.lock(); } //Perhaps it
could be const MutexWrapper& mut (?)
~MutexLocker( void ){ mut.unlock(); }
}

So that I want to sync acces to the variable
volatile unsigned cont
in the following piece of code (supposing there is a global
MutexWrapper mut ):

unsigned getCont( void )
{
MutexLocker( mut );
return( cont );
}

Will the destructor ~MutexLocker() be executed before the copy
constructor of unsigned? It seems logical if this return statement
could be interpreted as a placement new in the adress given by the
return variable, something like the equivalence of:

c = getCont();

and

{
MutexLocker( mut );
new( &c ) unsigned( cont );
}

If so, my code seems to be correct. Is it true?

Thanks,
Elias.
 
V

Victor Bazarov

[..]
unsigned getCont( void )
{
MutexLocker( mut );


Not sure what 'mut' here is, but if it's a global object of some
kind, then the statement above creates (and immediately discards)
a temporary value of type 'MutexLocker'. The destructor for that
temporary is called before the following 'return' statement is
exectuted.
return( cont );
}

Will the destructor ~MutexLocker() be executed before the copy
constructor of unsigned?

There is no "copy constructor of unsigned". Does all that clarify
the situation?
It seems logical if this return statement
could be interpreted as a placement new in the adress given by the
return variable, something like the equivalence of:

c = getCont();

and

{
MutexLocker( mut );
new( &c ) unsigned( cont );
}

If so, my code seems to be correct. Is it true?


V
 
J

Jim Langston

Sorry if this may seem to be very obvious, but it is important and I
decided to ask.

I have the following classes:

class MutexWrapper
{
public:
MutexWrapper( void );
void lock( void ); //Maybe const, whatever.
void unlock( void ); //As well.
~MutexWrapper( void );
}

class MutexLocker
{
public:
MutexLocker( MutexWrapper& mut ){ mut.lock(); } //Perhaps it
could be const MutexWrapper& mut (?)
~MutexLocker( void ){ mut.unlock(); }
}

So that I want to sync acces to the variable
volatile unsigned cont
in the following piece of code (supposing there is a global
MutexWrapper mut ):

unsigned getCont( void )
{
MutexLocker( mut );

You are not storing the instance of MutexLocker anywhere. It is created,
then prompty destroyed.
return( cont );

At this point your MutexLocker is already destroyed.
}

Will the destructor ~MutexLocker() be executed before the copy
constructor of unsigned? It seems logical if this return statement
could be interpreted as a placement new in the adress given by the
return variable, something like the equivalence of:

c = getCont();

and

{
MutexLocker( mut );
new( &c ) unsigned( cont );
}

If so, my code seems to be correct. Is it true?

You need to store your MutexLocker somewhere.

unsigned getCont( void )
{
MutexLocker LockIt( mut );
return( cont );
}

By giving the MutexLocker a variable name, its lifetime is the lifetime of
the function/method.

The quesiton still becomes, which is done first, the destruction of LockIt
or the retriving of the cont value? I'm not really sure, someone might
know. But being unsure I would do this.

unsigned getCont( void )
{
MutexLocker LockIt( mut );
unsigned ReturnVal = cont;
return( ReturnVal );
}

I know for a fact that ReturnVal is going to be assigned while the instance
of the MutexLocker is still there. It may not be necessary, but I know it
would work.
 
J

James Kanze

[..]
unsigned getCont( void )
{
MutexLocker( mut );
Not sure what 'mut' here is,

It doesn't matter.
but if it's a global object of some
kind, then the statement above creates (and immediately discards)
a temporary value of type 'MutexLocker'.

No. That statement declares a variable mut, of type
MutexLocker. If MutexLocker doesn't have a default constructor,
it is illegal, and the compiler should complain. If MutexLocker
does have a default constructor, then it is called.
The destructor for that
temporary is called before the following 'return' statement is
exectuted.

The destructor of mut is called on leaving the function.
There is no "copy constructor of unsigned". Does all that clarify
the situation?

Conceptually, cont can be copied, as if it had a copy
constructor. The destructor of the variable mut will be called
after this copy.
 
J

James Kanze

Sorry if this may seem to be very obvious, but it is important and I
decided to ask.
I have the following classes:
class MutexWrapper
{
public:
MutexWrapper( void );
void lock( void ); //Maybe const, whatever.
void unlock( void ); //As well.
~MutexWrapper( void );
}
class MutexLocker
{
public:
MutexLocker( MutexWrapper& mut ){ mut.lock(); } //Perhaps it
could be const MutexWrapper& mut (?)
~MutexLocker( void ){ mut.unlock(); }
}
So that I want to sync acces to the variable
volatile unsigned cont
in the following piece of code (supposing there is a global
MutexWrapper mut ):

Just curious as to what you thing the volatile is going to do
here. (Under Posix, at least, and supposing that your
MutexWrapper actually wraps a pthread_mutex_t, all it does is
slow up your code, without providing any additional guarantees.)
unsigned getCont( void )
{
MutexLocker( mut );

If the above compiles, it's time to change compilers.
MutexLocker doesn't have a default constructor, so you can't
declare an instance of it without providing an argument.
return( cont );
}
Will the destructor ~MutexLocker() be executed before the copy
constructor of unsigned?

Since the code won't compile, it's hard to say anything about
its runtime behavior. Local variables however, will only be
destructed after the return value has been copied to where ever
it is to be copied to.
 
P

__PPS__

It doesn't matter.

No, it does matter.
In the code MutexLocker could be a function or it could be a class
with similar use as scoped_lock (to lock a mutex on constructor and
unlock it on destructor). If it's a class, then there's a problem with
the code because this statement doesn't really lock scope of the
function, it will only wait until lock is released by other threads
and then will return immediately unlocking the mutex object because
the mutexlock object is nowhere and it will be destructed immediately.
You may check all that by stepping through the code with debugger.
No. That statement declares a variable mut, of type
MutexLocker. If MutexLocker doesn't have a default constructor,
it is illegal, and the compiler should complain. If MutexLocker
does have a default constructor, then it is called.

No, it's all wrong. Usually, mutexlocker by semantics has to be
noncopyable (no assignment or copy constructor) and non default
constructible too.
The destructor of mut is called on leaving the function.

No, it's wrong, destructor will be called right before the next line.

....
All these questions were clearly answered in previous posts, did you
try to read them at least??
I think you made a mistake thinking that MutexLocker ( mut ); is the
same as MutexLocker mut;
Just curious as to what you thing the volatile is going to do
here.

As far as I'm concerned volatile only removes optimizations in the
code that involves this variable (basically, if value of this variable
is stored in a cpu register and then if some operation should be
performed on the variable the stored value of the variable will not be
used - it will again be reloaded from memory because it's assumed that
the memory cell possibly was modified by other thread. BUT it doesn't
not guarantee at all any atomicity, e.g. some other thread may have
modified the variable and still didn't put the modified value back to
memory cell... http://en.wikipedia.org/wiki/Volatile_variable
 
V

Victor Bazarov

__PPS__ said:
[..]
I think you made a mistake thinking that MutexLocker ( mut ); is the
same as MutexLocker mut;

It is, if 'MutexLocker' is a type. I actually made a mistake of
thinking it would be a creation of a temporary object (that's all
*if* 'MutexLocker' is a type), but it isn't. Here is the test you
can run

class MutexLocker {
public:
MutexLocker() {} // default c-tor
MutexLocker(int) {} // parameterized c-tor
operator int() const { return 42; }
};

int mut = 0;

int main() {
MutexLocker(mut);
return mut;
}

What do you think this program's "main" will return to the system?
Please explain.

Another example, similar, of ill-formed code:

class MutexLocker {
MutexLocker() {} // default c-tor -- private!!!
public:
MutexLocker(int) {} // parameterized c-tor
};

int mut = 0;

int main() {
MutexLocker(mut); // should not compile
}

Now, if 'MutexLocker' is NOT a type but instead, say, a macro that
expands into something like

MutexLocker_t someUniqueVariableName123456(mut);

then further clarification may be required.

V
 
E

eshneto

As I see, this discussion is done with. I rewrote my code and initial
post as I meant and clarified the question based on the answers I got.
Two questions were answered: the one I actually wanted to ask and
another interesting one due to a typing error.

The typing error was to forget the name of the automatic variable to
be created, leaving the compiler to think that the argument I intended
to use for creation was the name of the object. I wrote

MutexLocker( mut ); //Fails on attempt to create an object named mut
//with default constructor.
//It does not create a temporary.

when I meant:

MutexLocker lock( mut );

where, as said, mut is a global MutexWrapper. The hole post is
rewritten here with comments on the answers, all of them tested.

First the post as I meant:
I have the following classes:

class MutexWrapper
{
public:
MutexWrapper( void ){ pthread_mutex_init( &_mut, NULL ); }
void lock( void ){ pthread_mutex_lock( &_mut ); }
void unlock( void ){ pthread_mutex_unlock( &_mut ); }
~MutexWrapper( void ){ pthread_mutex_destroy( &_mut );}

private:
pthread_mutex_t _mut;

}

class MutexLocker
{
public:
MutexLocker( MutexWrapper& mut ) : _mut( mut ) { mut.lock(); }
~MutexLocker( void ){ _mut.unlock(); }
private:
MutexWrapper& _mut;

}

So that I want to sync acces to the variable

volatile unsigned cont;

Which, by the way, is volatile because I do not want optimization to
mess loops such as while( cont < n );
I hope this answers one of Kanze's questions.
in the following piece of code, supposing there is a global
MutexWrapper mut:

Here was the error in my first post. Whatever that creepy piece of
code meant, it was not what I had in mind. The actual code is:
unsigned getCont( void )
{
MutexLocker lockIt( mut );
return( cont );
}

Will the destructor ~MutexLocker() be executed before the return statement?

Langston got the typing error, but still did not answer to the main
question:

"
By giving the MutexLocker a variable name, its lifetime is the lifetime of
the function/method.

The quesiton still becomes, which is done first, the destruction of LockIt
or the retriving of the cont value? I'm not really sure, someone might
know. But being unsure I would do this.

unsigned getCont( void )
{
MutexLocker LockIt( mut );
unsigned ReturnVal = cont;
return( ReturnVal );

}
"

Which was later answered by Kanze:

"
Conceptually, cont can be copied, as if it had a copy
constructor. The destructor of the variable mut will be called
after this copy.
"

In the same post he also clarifies the "default constructor versus
temporary creation" issue.

How did I test it?

By stepping through the correct code with gdb it becomes clear that
the return( cont ); statement is executed before the destructor for
lockIt.

Trying to compile the code given in my first post with g++ gives:

error: no matching function for call to 'MutexLocker::MutexLocker()'

because it is not defined at all, showing which constructor is
actually called.

Thanks,
Elias.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,290
Messages
2,571,453
Members
48,129
Latest member
DianneCarn

Latest Threads

Top