Re: destructors moved out of place ?
On 5 Mar., 16:13, viki...@gmail.com wrote:
On Mar 5, 4:48 pm, peter koch <peter.koch.lar...@gmail.com> wrote:
On 5 Mar., 15:18, viki...@gmail.com wrote:
On Mar 5, 2:59 pm, Michael DOUBEZ <michael.dou...@free.fr> wrote:
viki...@gmail.com a =E9crit :
I have a question whether compiler can move destructors past
the place when it's normal out-of-scope place is. Is this true ?
Example:
I have a lock/unlock wrapped into the object SafeLock,
where SafeLock::SafeLock() { m_lock.Lock(); }
and SafeLock::~SafeLock() { m_lock.Unlock();=
}
void Class::Method(void) {
SafeLock lock; // lock in ctor, unlocks in dto=
r
......
// (1) lock is automatically unlocked here, ok=
..
}
So far, so good. The lock is unlocked at point (1), when it goes o=
ut
of scope.
Now let's look at the more complex case, with innner block:
void Class::Method(void) {
......
{ // inner block
SafeLock lock; // (4)
} // (5)
... // (6)
}
Normally, lock(4) is destroyed at (5).
But I was told this is not necessarily so;
that C++ compiler is free to delay destruction of lock
until later, until end of bigger bklock at (6).
Is this true ? Is it indeed allowd ? I have difficulty to believe
that
standard allows this. Indeed, destructors can have side effects li=
ke
closing files.
The compiler could delay the destruction of the object if the overal=
l
behavior is the same (as you said, if there is no side effect).
You are right, the lock is unlocked at (5).
Is it possible to have standard reference that explicitly
prohibits this "optimization" ?
The relevant parts are =A712.4-10:
Destructors are invoked implicitely [...] for a constructed object w=
ith
automatic storage duration (3.7.2) when the block in which the objec=
t
exits [...]
And =A73.7.2-3:
If a named object has initialization or a destructor with side effec=
ts,
it shall not be destroyed before the end of its block
^^^^^^
Hmmm stange wording. It says "not before".
"Shall not be destroyed before end of its block".
But it does not say "not after".
Well, I believe the standard is quite clear - and all was quoted by
Michael:
Destructors are invoked implicitely [...] for a constructed object w=
ith
automatic storage duration (3.7.2) when the block in which the objec=
t
and:
If a named object has initialization or a destructor with side effec=
ts,
it shall not be destroyed before the end of its block
so it must not be destroyed before ever - not even if it looks as it
is unused.
So as Michael said, it is destroyed at exactly the point where the
scope ends.
So the destructor is implicitly invoked when the block exits.
Shall we interpreted it as permission to
invoke the destructor with side effects
*after* end of the block ? What good would be this for ?
I can see situations where this could be bad.
Victoria
, nor shall it be
eliminated as an optimization even if it appears to be unused, excep=
t
that a class object or its copy may be eliminated as specified in 12=
..8.
So the destructor is implicitly invoked when the block exits.
I do not see what you see. Optimizers are known to shuffle pieces of
code around.
People *observed* the destructors to be invoked at the end and
*bigger* block
because optimizer moved it and supposedly because standard does not
disabllow it
such optimizations *especially* for no-side-effects destructor.
I do not mind optimizer shuffling around the no-side-effect
destructors
(provided that behaviour is preserved).
For side-effects destructor, Michael showed that standard disallows
moving the destructor invocation to *earlier* point.
To me, that looks like permission for the optimizer to
move destructor invocation to the later point, for side-effects dtors,
and
(2) to move the no-side-effects dtors invocation forward or backward
(conditioned that it preserves results and behaviour, of course).
I *do not* see where standard disallows the optimizer to move
the side-effect destructor to later point. Where do you see this ?
The way I read the "Destructors are invoked implicitely [...] for a
constructed object with
automatic storage duration (3.7.2) when the block in which the object
exits " is quite clear. "when" indicates a point in time and can not
be later.
And given that people observed that optimizer moved destructor
invocation
to the end of *bigger* block, my question still remains, is this
standard conformant, and does it make the diffence whether dtor has
side effects or not wrt standard conformance ?
If there was observable behaviour, the compiler would have a bug.
There is absolutely no doubt about this, and I frankly doubt that this
has been observed with any newer compiler. The idiom shown is so
common that tons of code would break if standard behaviour was not
followed. I am one of the many using the idiom shown as in your
example - with locks. And I have NEVER had an indication that that
should not work. It has never failed, and I've never seen an assembly
listing where the above did not hold. But I do vaguely remember that
VC 6.0 had a bug that prevented us from using it with all
optimisations on (dont remember if the above was one of the problems).
If you use that compiler it is just possible that you need to be
careful.
/Peter