Topic: destruction of temporaries


Author: bill@sunquest.UUCP (Bill Raves)
Date: 12 Aug 92 23:31:55 GMT
Raw View
We have encountered some widely different behavior in compilers (e.g.
DEC C++ and cfront) with respect to the destruction of unnamed temporaries
in contexts where a pointer or reference to object data is returned.
We realize that compiler implementors have been given latitude in this
area (see $12.2 of the ARM) and that the ANSI C++ standards committee is
discussing this issue. We also realize that the manifestations of this
behavior may introduce subtle bugs in code. The question is "How can
we prevent these problems from getting into production code?".

One suggestion is to promulgate stylistic guidelines which caution
against troublesome usage. For example, Jim Adcock has suggested
(<70784@microsoft.UUCP>) "NEVER rely on unnamed temporaries to do
anything...", but this would seem to erode the expressiveness of the
language: constructs like "foo(x + y)" and "foo()[i]" would no longer
be permissible. Henricson & Nyquist suggest "Do not write code which is
dependent on the lifetime of a temporary object" but this seems too
vague, especially for novice programmers, and seems to require us to
know the details of the implementation.  What *specific* guidelines
would you suggest for avoiding potential problems with unnamed tem-
poraries?


--
Bill Raves    bill@sunquest.com
Sunquest Information Systems  sunquest!bill@arizona.edu
Tucson, AZ                              {arizona,uunet}!sunquest!bill




Author: kelley@mpd.tandem.com (Michael Kelley)
Date: 16 Oct 91 15:15:18 GMT
Raw View
Although the 1st edition ARM explicitly states that the time at which
temporaries
are destroyed is implementation dependent, I wonder if in fact there
won't at least
be an implicit rule-of-thumb dictated by exception handling.  I have managed to
implement something very much like E&S exception handling for cfront-based
translation (with no modification to cfront itself), but got bit the other
day when cfront did not order temporary destruction in the inverse of the order
of construction.  It is the only case we happened to have stumbled on so
far; if
you know of others, I would appreciate the input.  Also, if the ANSI committee
members have changed their tune on this matter, or might be inclined to do so,
please let me know. Given enough feedback, I'll post responses.  For
your viewing pleasure (ha ha ha) is some test code and it's output --
it's case #2 that caused
the problem under both cfront 2.0 and 2.1.


=================  file hello.C ============================

#include <iostream.h>

class Foo {
public:
    Foo(int i);
    ~Foo();
};

Foo::Foo(int i)
{
    cout << "Foo::Foo(" << (void *) this << ", " << i << ")" << endl;
}

Foo::~Foo()
{
    cout << "Foo::~Foo(" << (void *) this << ")" << endl;
}

class Bar {
public:
    Bar(const Foo&);
    ~Bar();
};

Bar::Bar(const Foo&)
{
    cout << "Bar::Bar(" << (void *) this << ", const Foo&)" << endl;
}

Bar::~Bar()
{
    cout << "Bar::~Bar(" << (void *) this << ")" << endl;
}


void f(const Bar&)
{ }


main()
{
    {
        Foo foo(1);     // explicit temporary: ok
        f(Bar(foo));
    }
    cout << endl;
    {
        f(Bar(2));      // implicit innermost constructor: ???
    }
    cout << endl;
    {
        f(Foo(3));      // implicit outermost constructor: ok
    }
    cout << endl;
    {
        f(Bar(Foo(4))); // both constructors explicit: ok
    }
}


========= output from hello.C =====================

Foo::Foo(0xf7fff74f, 1)
Bar::Bar(0xf7fff74b, const Foo&)
Bar::~Bar(0xf7fff74b)
Foo::~Foo(0xf7fff74f)

Foo::Foo(0xf7fff74e, 2)
Bar::Bar(0xf7fff74f, const Foo&)
Foo::~Foo(0xf7fff74e)
Bar::~Bar(0xf7fff74f)

Foo::Foo(0xf7fff74f, 3)
Bar::Bar(0xf7fff74e, const Foo&)
Bar::~Bar(0xf7fff74e)
Foo::~Foo(0xf7fff74f)

Foo::Foo(0xf7fff74f, 4)
Bar::Bar(0xf7fff74e, const Foo&)
Bar::~Bar(0xf7fff74e)
Foo::~Foo(0xf7fff74f)

Mike Kelley
Tandem Computers, Austin, TX
kelley@mpd.tandem.com
(512) 244-8830 / Fax (512) 244-8247