Topic: Evaluation of return expression


Author: jimad@microsoft.com (Jim Adcock)
Date: 23 Sep 93 20:05:33 GMT
Raw View
In article <27fnq6$seg@net1.ics.uci.edu> schmidt@ics.uci.edu (Douglas C. Schmidt) writes:
| Can someone please tell me if the return expression from a
|function is guaranteed to be fully evaluated *before* any destructors
|are called....

Yes.  The return expression is evaluated *in* the scope of the function.
Dtors are evoked *at exit* from the scope of the function.  IE the
return expression must be evaluated before the return is performed,
and the scope of the function is exited.




Author: schmidt@net1.ics.uci.edu (Douglas C. Schmidt)
Date: 18 Sep 1993 12:33:26 -0700
Raw View
Hi,

 Can someone please tell me if the return expression from a
function is guaranteed to be fully evaluated *before* any destructors
are called, e.g., is the following guaranteed to work correctly:

----------------------------------------
int
List::get_count (void)
{
  Monitor m (this->lock); /* Monitor m starts out locked */
  return this->count;
  /* Implicit destructor call which unlocks monitor m */
}
----------------------------------------

 Obviously, if the lock is released before `this->head' is
evaluated there could be race condition problems.  I'm assuming that
C++ dictates that the destructor be called *after* the return
expression is evaluated, but it would be nice to know for sure before
utilizing this technique throughout my design!

 thanks,

  Doug
--
His life was gentle, and the elements so            | Douglas C. Schmidt
Mixed in him that nature might stand up             | schmidt@ics.uci.edu
And say to all the world: "This was a man."         | ucivax!schmidt
   -- In loving memory of Terry Williams (1971-1991)| (714) 856-4101




Author: whitney@oberon.Meakins.McGill.CA ()
Date: Sun, 19 Sep 1993 03:34:20 GMT
Raw View
Douglas C. Schmidt (schmidt@net1.ics.uci.edu) wrote:
: Hi,

:  Can someone please tell me if the return expression from a
: function is guaranteed to be fully evaluated *before* any destructors
: are called, e.g., is the following guaranteed to work correctly:

: ----------------------------------------
: int
: List::get_count (void)
: {
:   Monitor m (this->lock); /* Monitor m starts out locked */
:   return this->count;
:   /* Implicit destructor call which unlocks monitor m */
: }
: ----------------------------------------

:  Obviously, if the lock is released before `this->head' is
: evaluated there could be race condition problems.  I'm assuming that
: C++ dictates that the destructor be called *after* the return
: expression is evaluated, but it would be nice to know for sure before
: utilizing this technique throughout my design!

Heck ! even

 return C++;

doesn't work.




Author: vinoski@apollo.hp.com (Steve Vinoski)
Date: Mon, 20 Sep 1993 15:11:03 GMT
Raw View
In article <27fnq6$seg@net1.ics.uci.edu> schmidt@ics.uci.edu (Douglas C. Schmidt) writes:
> Can someone please tell me if the return expression from a
>function is guaranteed to be fully evaluated *before* any destructors
>are called, e.g., is the following guaranteed to work correctly:
>
>----------------------------------------
>int
>List::get_count (void)
>{
>  Monitor m (this->lock); /* Monitor m starts out locked */
>  return this->count;
>  /* Implicit destructor call which unlocks monitor m */
>}
>----------------------------------------
>
> Obviously, if the lock is released before `this->head' is
>evaluated there could be race condition problems.  I'm assuming that
>C++ dictates that the destructor be called *after* the return
>expression is evaluated, but it would be nice to know for sure before
>utilizing this technique throughout my design!

I brought exactly this same problem up in this very forum several
months ago, but unfortunately I didn't receive what I would consider
to be a definitive answer.

In the second edition of The C++ Programming Language, Stroustrup
advocates the "resource acquisition is initialization" approach
(section 9.4, page 308).  Doug's example above is a form of this
approach; it acquires a lock via monitor initialization, performs some
work, then counts on the monitor destructor to release the lock.  The
result of the function is intended to be the value of "count" *while
the lock is held*.  However, it is clear from the example that the
"resource acquisition is initialization" approach can fail in some
instances unless return expressions are guaranteed to be evaluated at
the proper time.

The 06/01/93 draft states that "a return statement with an expression
can be used only in functions returning a value; the value of the
expression is returned to the caller of the function."  On the
surface, it would seem that any compiler that does not return the
value of "count" that exists before the monitor object is destroyed is
broken.

Unfortunately, since C++ lacks sequence points (to my knowledge), this
is very hard to prove.  Even if there were sequence points, unless
"count" is volatile, simply accessing it does not constitute a side
effect that must completed by the next sequence point (see section
2.1.3.2 of the ANSI C standard).

The approach taken in Doug's example will become more and more
pervasive as exceptions become more widely available, and as more
people work with multi-threaded systems.  It seems like we at least
need sequence points before the "resource acquisition is
initialization" approach can work properly.  Anybody know the status
of adding sequence points to the draft?

--steve

Steve Vinoski  vinoski@apollo.hp.com    (508)436-5904
Distributed Object Computing Program    fax: (508)436-5122
Hewlett-Packard, Chelmsford, MA 01824




Author: kanze@us-es.sel.de (James Kanze)
Date: 20 Sep 93 19:40:01
Raw View
In article <27fnq6$seg@net1.ics.uci.edu> schmidt@net1.ics.uci.edu
(Douglas C. Schmidt) writes:

|>  Can someone please tell me if the return expression from a
|> function is guaranteed to be fully evaluated *before* any destructors
|> are called, e.g., is the following guaranteed to work correctly:

|> ----------------------------------------
|> int
|> List::get_count (void)
|> {
|>   Monitor m (this->lock); /* Monitor m starts out locked */
|>   return this->count;
|>   /* Implicit destructor call which unlocks monitor m */
|> }
|> ----------------------------------------

|>  Obviously, if the lock is released before `this->head' is
|> evaluated there could be race condition problems.  I'm assuming that
|> C++ dictates that the destructor be called *after* the return
|> expression is evaluated, but it would be nice to know for sure before
|> utilizing this technique throughout my design!

The ARM says: "Destruction of local variables declared in the block is
done on exit from the block."  If taken literally, I would interpret
this to mean that the local variables can only be destructed *after*
the actual return.  At any rate, I would interpret it to mean that the
return'ed expression must be evaluated *before* the local variables
are destroyed.

I think it safe to suppose that this interpretation will prevail.  The
alternatives would break too much code.
--
James Kanze                             email: kanze@us-es.sel.de
GABI Software, Sarl., 8 rue du Faisan, F-67000 Strasbourg, France
Conseils en informatique industrielle --
                   -- Beratung in industrieller Datenverarbeitung




Author: cok@acadia.Kodak.COM (David Cok)
Date: Mon, 20 Sep 93 18:35:07 GMT
Raw View
In article <KANZE.93Sep20194001@slsvhdt.us-es.sel.de> kanze@us-es.sel.de (James Kanze) writes:
>
>The ARM says: "Destruction of local variables declared in the block is
>done on exit from the block."  If taken literally, I would interpret
>this to mean that the local variables can only be destructed *after*
>the actual return.  At any rate, I would interpret it to mean that the
>return'ed expression must be evaluated *before* the local variables
>are destroyed.
>
>I think it safe to suppose that this interpretation will prevail.  The
>alternatives would break too much code.
>--

To be even more careful about it, the destructors need to be called after
the copy constructor (if any) which copies the evaluated result.

DRC