Path: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!csd4.milw.wisc.edu!bionet!ames!haven!adm!cmcl2!lanl!lambda!scp From: scp@raven.lanl.gov (Stephen Pope) Newsgroups: comp.lang.c++ Subject: Re: Generating temporaries Message-ID: Date: 4 Apr 89 22:29:57 GMT References: <7.UUL1.2#261@persoft.UUCP> Sender: news@lanl.gov Organization: The Santa Fe Institute, NM Lines: 70 In-reply-to: ericf@persoft.UUCP's message of 4 Apr 89 14:10:37 GMT In article <7.UUL1.2#261@persoft.UUCP> ericf@persoft.UUCP (Eric R. Feigenson) writes: [I'm rather new to C++, so this may be a rather naive query. Please bear with me] I have a class M for which I want to define operator+. My question(s) have to do with how I generate the temporary that contains the result, and how such a temporary gets destroyed. Not at all trivial. Any and all who have tried to create a usable Vector/Matrix library can tell you so. If you have followed the recent discussions of Doug Lea et al. here concerning constructor idempotency and the "X x ( f() );" vs "X x = f();" problem, you will find that there is no *robust* solution, whether or not you use reference counting. The problem is that your object (class X) needs to identify itself as being "bound" (as a storage area to a symbol, like X x), or unbound (a function return value, for example, operator+() included). This can be handled in two ways: 1) Create a parallel "tmpX" class, define all functions normally returning an X as returning an tmpX, and then supply the appropriate X::X(tmpX&) and X::operator=(tmpX&) routines which understand how to reuse storage space and data. This actually works well, but with a class hierarchy of more than two or three derived classes and a small handful of object- returning functions/operators, the combinatorics quickly get out of hand. Besides, who wants to write: tmpMatrix Matrix::operator+(Matrix&, Matrix&); 2) Include a "temporary" flag in each object, along with constructors and assignment operators (and any other "smart" operators) that check this flag and steal data/storage when appropriate. Unfortunately, because constructor semantics are still marginally defined (or, to avoid 3rd degree burns, should I say "defined by their implementation"), it is not possible to "count constructors" on the way out of class-object-returning functions and through the succeeding constructor(s)/assignments. Furthermore, you cannot avoid having to use some manner of "smart" return statement from such functions, which mark the returned value as being reusable (temporary). Straight reference counting schemes, which actually pass around some sort of pointer object to another object with the data storage with built in reference counting (and suicide for garbage collecting) fall short whenever assignment is an important operation of class objects, as in Matrix classes. Furthermore, as cfront 1.2 delays the destruction of *hidden* temporaries (used for function return values) until the close of the innermost enclosing block, you'll discover some surprising inefficiencies because references you thought were gone are actually still fully alive, forcing unneccesary copying of data and/or allocation of new storage space. If you have watched the evolution of Doug Lea's Matrix package (still an *experimental* baby), you will have seen much of this hashed out. The problems have proven so acute that for the time being, responsability for temporary control and storage reuse has been largely pushed back onto the class user, an unfortunate but seemingly necessary evil (at least until constructor semantics are a little better defined/implemented). Stephen C. Pope Disclaimer: The Santa Fe Institute "Employer? What employer?" scp@sfi.santafe.edu