[comp.lang.c++] C++ coding standards

edward@runxtsa.runx.oz.au (Edward Birch) (08/12/90)

A friend of mine works with a large organization where they have defined a
standard that "variables must be declared where first used".

I think that this is an absolutely insane standard for the following reasons:

	o The declarations clutter the algorithm. 

	o Most C and C++ programmers are used to seeing variables declared
	  in one place. I believe that changing this will only add to
	  maintenance costs and development time.
	  C has had the ability to declare variables at the start of each
	  block. How often is it used ? Why isn't it used ?

	o I have found that declaring variables where they are first used
	  significantly adds to the development time of code. With little
	  benefit to the over all presentation of the code.

	o I also find that declaring variables at the start of functions
	  in one spot to significantly adds to the readability of the code.

I would be extremely interested in feedback.

Edward Birch

Phone:  +612 2 958-2119

UUCP:   seismo!munnari!runx.oz!edward   ACSnet:  edward@runx.oz
ARPA:   edward%runx.oz@seismo.css.gov   CSNET:   edward@runx.oz
-- 
Telex: 10713856 BRHT

UUCP:   seismo!munnari!runx.oz!edward   ACSnet:  edward@runx.oz
ARPA:   edward%runx.oz@seismo.css.gov   CSNET:   edward@runx.oz

gregk@cbnewsm.att.com (gregory.p.kochanski) (08/13/90)

In article <2161@runxtsa.runx.oz.au> edward@runxtsa.runx.oz.au (Edward Birch) writes:
>A friend of mine works with a large organization where they have defined a
>standard that "variables must be declared where first used".
>
>I think that this is an absolutely insane standard for the following reasons:

Well, I'm not a true expert, but I've been using that coding style in both
C and C++ for several years voluntarily, and I like it.
It makes you think about just where you need this data, and there's less
flipping around in the text editor looking for the declaration, as it's often
on the same screen.   I suppose it's a matter of taste.
Of course, if you have small functions, this becomes a moot point.

Greg Kochanski gpk@physics.att.com
AT&T Physics Research -- Physics for fun and profit.

zmls04@trc.amoco.com (Martin L. Smith) (08/13/90)

We have just started to move from C to C++ and the declare-at-usage
style still looks a little strange.  I've noticed a tendency in my own
code to declare throwaway variables (the index in a loop, say) when
they are used but to group more significant ones in declaration
chunks, which are not always at the start of a function block.
I've noticed at least two drawbacks in this style:

1 - It's cowardly and has no really clear principles.

2 - Declaring loop indices at point of use leads to some problems in my
	case, at least, because I tend to reuse i, j, etc, and C++ doesn't
	like repeated declarations (at least in the first clause of a
	for-loop).  The second for loop that uses 'i', for example, should
	not declare it.  If I later delete the first loop then I have to remember
	to add the declaration to the new first loop (the old second loop,
	that is [are you still there?]) or I get a compile error.  This symptom
	strikes me as an indication that this style is not the best we could do.

Anyhow, I too would really like to read more discussion on this issue.
--

   Martin L. Smith             Amoco Research Center
                               P.O. Box 3385
 zmls04@trc.amoco.com          Tulsa, OK 74102
[zmls04@sc.msc.umn.edu]        918-660-4065

bmcphers@alias.UUCP (Brent McPherson) (08/14/90)

In article <2161@runxtsa.runx.oz.au> edward@runxtsa.runx.oz.au (Edward Birch) writes:
>A friend of mine works with a large organization where they have defined a
>standard that "variables must be declared where first used".
>
>I think that this is an absolutely insane standard for the following reasons:
>[reasons deleted]

I have to disagree with you. There are important reasons for not doing this
in C++.  If all variables in C++ were declared at the start of a routine,
then all the constructors/destructors would get executed on each invocation
of the routine (even if the variables are not used because of control flow
within the routine). The problem is also worse because of nested constructors
and destructors with inherited classes.

A better plan would be to declare all variables at the start of each block
so objects that aren't used (depending on which blocks are executed)
don't have their constructors/destructors called. This distributes the cost
evenly over the entire routine and can result in less overhead in most cases
(rather than a large, constant cost at entry/exit of the routine).

I also like having variables declared close to where they are used since you
will be less likely to forget to remove old variable declarations as the
code evolves. This is not so much of a problem these days since most compilers
will warn of unused/uninitialized variables.

Finally, common sense should prevail. If a variable is first assigned a value
within a loop it should be declared outside the loop just in case the compiler
decides to create the variable on the stack for each loop iteration.

BTW. I think constant cursoring to the top of a routine to add/delete/modify
variables increases development time. Also, readability/understandability are
a matter of personal preference (remember the brace/format/spacing debates
between various C programmers).

>Edward Birch

--
Brent McPherson
Alias Research Inc.
bmcphers%alias@csri.toronto.edu

jimad@microsoft.UUCP (Jim ADCOCK) (08/14/90)

In article <2161@runxtsa.runx.oz.au> edward@runxtsa.runx.oz.au (Edward Birch) writes:
>A friend of mine works with a large organization where they have defined a
>standard that "variables must be declared where first used".
>
>I think that this is an absolutely insane standard for the following reasons:
....

I believe the major goal should be to initialize where declared.  Since
some initialization values are computed down-stream in a function, some
declarations have to placed down-stream.  The general rule my group uses
is to move declarations into the smallest scope reasonable.  If one keeps
one's functions small, then any declaration strategy should work.  If a 
variable is used through-out a function, continue to declare that variable
at the start of the function.

ark@alice.UUCP (Andrew Koenig) (08/15/90)

In article <2161@runxtsa.runx.oz.au> edward@runxtsa.runx.oz.au (Edward Birch) writes:
> A friend of mine works with a large organization where they have defined a
> standard that "variables must be declared where first used".

`Must' is too strong, but I do think there is often an advantage
to declaring a variable at its first use.  For example:

	void f()
	{
		int i;

		// a bunch of code

		if (i > 0)
			g();

		// ...
	}

Is the test `i > 0' valid or not?  The answer is that it's valid if and
only if something in `a bunch of code' initialized `i.'

That is, during at least part of `a bunch of code,' variable `i'
exists but is uninitialized.

If `i' were initialized at its point of declaration, it would
never be uninitialized.  In other words, if you initialize all
your variables when you declare them, they won't be uninitialized.

Now one might argue that this is just a matter of taking care to
get it right.  After all, uninitialized variables aren't always
dangerous -- you just have to make sure not to use them until
you've initialized them.  But many classes initialize things
for you:

	String s;

	// ...

	s = "hello";

With every String class I've seen, `s' will be initialized to
the null string at its declaration.  Later that initial value
must be discarded and replaced with "hello" .  It is almost
always faster to say

	// ...

	String s = "hello";

As to the argument that it's harder to find declarations if they're
scattered through your functions: if your function is so big that it
matters, you should probably split it up anyway.
-- 
				--Andrew Koenig
				  ark@europa.att.com

gwu@nujoizey.Berkeley.EDU (George Wu) (08/16/90)

In article <2161@runxtsa.runx.oz.au>, edward@runxtsa.runx.oz.au (Edward
Birch) writes:
|> A friend of mine works with a large organization where they have defined a
|> standard that "variables must be declared where first used".
|> 
|> I think that this is an absolutely insane standard . . .

     I must agree with you.  We have no such standard, and so I see all
kinds.  I find that the interspersed declarations really do cloud the issue.
And especially when you have multiple programmers working together, you MUST
take maintenance issues into consideration.  I find myself screaming when I
am debugging someone else's code, I want to find the declaration of a
variable, and I find myself forced to wade through the code.  This is made
worse by the fact that often the variables are defined somewhere in the
class hierarchy.  But I, of course, still have to parse all the damn code.
The only helpful points are that most people at least try to limit the
length of routines, and modern editors can do string searches.

     As for the practice of declaring variables inside a block, ie. within a
pair of curly braces, I used to do so to minimize the scope of the variable
and clearly designate the variable for use only under certain conditions.
For example, I might do something like:


	switch (fooCode) {
	case BAR:
		{
			char *ascii;

			// some complex mess ...
		}
	case BAZ:
		{
			char *ebcdic;
			// ...
		}
	}


     HOWEVER, I soon discovered that I was doing so because the bloody
routine was getting too large.  The excess size of the routine is what made
restricted scoping use advantageous.  The REAL solution was to break down
the routine into smaller routines.

						George

----
George J Wu                           | gwu@tcs.com or ucbcad!tcs!gwu
Software Engineer                     | 2121 Allston Way, Berkeley, CA, 94704
Teknekron Communications Systems, Inc.| (415) 649-3752

jimad@microsoft.UUCP (Jim ADCOCK) (08/17/90)

In article <1990Aug13.182226.24141@alias.uucp> bmcphers@alias.UUCP (Brent McPherson) writes:
>Finally, common sense should prevail. If a variable is first assigned a value
>within a loop it should be declared outside the loop just in case the compiler
>decides to create the variable on the stack for each loop iteration.

Hm, I'm not sure I understand what you're trying to say here.  In the 
following code:

	for (int i=0; i<1000; ++i)
	{
		FOO foo(i);
		foo.DoSomething();
	}

It is certainly not the case that a thousand foos reside simultaneously
on the stack.  Rather, it is guaranteed that an object is destroyed as 
its constructor is jumped back over.  Thus, while conceptually there
are a 1000 foos, only one is in existance at any point in time, and they
all reside at the same location on the stack. 

mat@mole-end.UUCP (Mark A Terribile) (08/17/90)

> A friend of mine works with a large organization where they have defined a
> standard that "variables must be declared where first used".

> I think that this is an absolutely insane standard for the following reasons:

Let me add my voice to those who have have supported this standard (which
ought to be a guideline rather than a standard.)
 
> 	o The declarations clutter the algorithm. 

The declarations usually look just like an assignment with the type name
to the left of the assignment expression.  In the case of types which must
be initialized with multiple constructor arguments, you probably cannot
declare the variable ahead of time.
 
> 	o Most C and C++ programmers are used to seeing variables declared
> 	  in one place. I believe that changing this will only add to
> 	  maintenance costs and development time.
> 	  C has had the ability to declare variables at the start of each
> 	  block. How often is it used ? Why isn't it used ?

I worked for several years on a medium-sized (150 000) project that had gone
through many years of maintenance and enhancement, including a port from
assembler into C.  One of the things that kept the code clear and reasonably
safe between the occasional rewrites of various parts of the code (which
usually occurred when developers ganged up on management and testified that
they couldn't review the code well enough otherwise) was keeping all variables
in the smallest scope possible.

It's done, it works, and it saves a great deal of time in debugging and code
review.  It also ensures that someone won't accidently use a variable that
was used to hold an intermediate value in some small computation when they
want to use one of the variables that describes the environment in which the
function is operating.  Reducing the scope of variables to the minimum
necessary reduces the number of needless symbols in scope at any given time;
if functions exceed about 16 lines, this starts to make a big difference in
safety during maintenance and enhancement.  It helps to show how the `long-
range' communications represented by variables are tied to the `flow-of-
control' (Governs-Invokes) structure of the program.

And yes, we had functions that were several hundred lines long and that
would have been very difficult to split.  (In C++, with class scope as
an instance record, it would have been easier.)  These functions typically
broke down into five or six more or less linear steps, each of which was
fairly complicated and had a number of special rules that were invoked if
certain conditions occurred in previous steps.  Being able to declare
variables at the point where their initial values became available would
have made this code much safer.  So would consts.  (Only about a dozen
functions were this long; most were between ten and forty lines.)
 
> 	o I have found that declaring variables where they are first used
> 	  significantly adds to the development time of code. With little
> 	  benefit to the over all presentation of the code.

I found otherwise, both on small projects and on that largish piece of very-
real-world code.  (It's running in several tens of thousands of copies of
a business PBX.)  Adopting this style improved the review process; the
combination of an informal (but conscientious) review process and code
style improvements such as this reduced the number of trouble reports that
came back as new bugs by probably a factor of four.
 
> 	o I also find that declaring variables at the start of functions
> 	  in one spot to significantly adds to the readability of the code.

I find otherwise IF the code starts out highly readable.  This means
(among other things) that related computations are grouped and set aside
from other computations by white space.  If your code reads like good
prose, in which each paragraph develops one idea in a more or less linear
way, with each computation using the results just computed and providing
results that are used immediately thereafter, the inserted declarations
(which are usually just type names) will state clearly that this is a
new datum holding just this value, not the revision of some previous
value.  That the datum exists just to hold this value can be reinforced
by making it a  const .
-- 

 (This man's opinions are his own.)
 From mole-end				Mark Terribile

sysop@tlvx.UUCP (SysOp) (08/19/90)

In article <ZMLS04.90Aug13091620@gpss31.trc.amoco.com>, zmls04@trc.amoco.com (Martin L. Smith) writes:
> We have just started to move from C to C++ and the declare-at-usage
> style still looks a little strange.  I've noticed a tendency in my own
> code to declare throwaway variables (the index in a loop, say) when
> they are used but to group more significant ones in declaration
> chunks, which are not always at the start of a function block.
> I've noticed at least two drawbacks in this style:
> 
> 1 - It's cowardly and has no really clear principles.

Wouldn't the principal be that it's easier to program on-the-fly (er, so
to speak)?  It's not so bad putting everything at the top if I'm in an
editor that easily lets me enter into different windows....

> 
> 2 - Declaring loop indices at point of use leads to some problems in my
> 	case, at least, because I tend to reuse i, j, etc, and C++ doesn't
> 	like repeated declarations (at least in the first clause of a
> 	for-loop).  The second for loop that uses 'i', for example, should
> 	not declare it.  If I later delete the first loop then I have to remember
> 	to add the declaration to the new first loop (the old second loop,
> 	that is [are you still there?]) or I get a compile error.  This symptom
> 	strikes me as an indication that this style is not the best we could do.

I'm just starting to learn C++, and in making very simple programs, I ran
into this very problem!  Part of me really likes the convenience, but it 
seems to me that in the 2nd loop, that if I say "for (int loop=0..." and
it is already declared, as long as the delarations match (they're both
ints), it might as well use the same variable.  (Am I missing something?)

I mean, it's hard to argue that that would be a casual thing to do, since
declaring at first use is casual anyway.  It seems a pretty small matter, but
as a bug, it bit me enough for me to remember it.

On a related topic, in C, you can declare a variable anytime you open a
brace ("{").  This seems like a neat idea, since code within braces is more
likely to move as a unit.  (To get around the problems, I guess you would
surround a for loop with a set of braces external to that, then put the
declaration, and then the for, but by the time you do all that, it just
clutters things up, so why bother?)

I guess if it's too messy, you could avoid it, like avoiding the goto, or
at least list situations where it's not so messy.

> 
> Anyhow, I too would really like to read more discussion on this issue.
> --
> 
>    Martin L. Smith             Amoco Research Center
>                                P.O. Box 3385
>  zmls04@trc.amoco.com          Tulsa, OK 74102
> [zmls04@sc.msc.umn.edu]        918-660-4065

--
Gary Wolfe, SYSOP of the Temporal Vortex BBS
..uflorida!unf7!tlvx!sysop, ..unf7!tlvx!sysop@bikini.cis.ufl.edu

drk@athena.mit.edu (David R Kohr) (08/19/90)

In this discussion of the benefits and drawbacks of declaring variables
at their point of use in a block in C++, rather than at the beginning 
of a block as is required in C, I don't recall anyone making the
following point: you can't jump (using "goto") past a declaration with an 
initializer unless that declaration is within a block nested within the
current block.  (This is according to Stroustrup, _The_C++_Programming_
Language_, p. 296, section 9.11 of the C++ reference manual chapter;
I assume it's still true in AT&T C++ 2.0, but I don't have any
reference for that version on hand.)

There are those of us who occassionally use "goto" for efficiency 
reasons (or even to make the code clearer).  It seems awkward and
error-prone to me to have to consciously avoid jumping over declarations
with initializers each time one uses a "goto", and to have to check
that each declaration with an initializer is not in a code segment which 
can possibly be skipped over by a "goto".  Such awkwardness does not
lend itself to making code more maintainable.

This subtle mistake probably does not appear very often in practice, since the
"goto" is not used with great frequency in C++, but when it does appear
it is probably fairly difficult for the programmer to detect, much like use 
of an uninitialized variable.  However, compilers can easily detect 
instances of the use of uninitialized variables, while detecting the "goto" 
error requires a more extensive analysis of the code's flow-of-control.

--
David R. Kohr     M.I.T. Lincoln Laboratory      Group 45 ("Radars 'R' Us")
    email:    DRK@ATHENA.MIT.EDU (preferred)  or  KOHR@LL.LL.MIT.EDU
    phone:    (617)981-0775 (work)	      or  (617)527-3908 (home)

barmar@think.com (Barry Margolin) (08/19/90)

In article <56642@microsoft.UUCP> jimad@microsoft.UUCP (Jim ADCOCK) writes:
>In article <1990Aug13.182226.24141@alias.uucp> bmcphers@alias.UUCP (Brent McPherson) writes:
>>Finally, common sense should prevail. If a variable is first assigned a value
>>within a loop it should be declared outside the loop just in case the compiler
>>decides to create the variable on the stack for each loop iteration.
>It is certainly not the case that a thousand foos reside simultaneously
>on the stack.  Rather, it is guaranteed that an object is destroyed as 
>its constructor is jumped back over.  Thus, while conceptually there
>are a 1000 foos, only one is in existance at any point in time, and they
>all reside at the same location on the stack. 

However, the compiler might decide to grow and shrink the stack frame each
time the variable is created and destroyed.  Also, if the constructor
and/or destructor do anything expensive (e.g. use "new" and "delete" on
members of the object) this will be done each time through the loop, when
it probably would be OK to reuse a single object.

--
Barry Margolin, Thinking Machines Corp.

barmar@think.com
{uunet,harvard}!think!barmar

jamshid@walt.cc.utexas.edu (Jamshid Afshar) (08/21/90)

In article <1990Aug19.160307.20972@athena.mit.edu> drk@athena.mit.edu (David R Kohr) writes:
>
>In this discussion of the benefits and drawbacks of declaring variables
>at their point of use in a block in C++, rather than at the beginning 
>of a block as is required in C, I don't recall anyone making the
>following point: you can't jump (using "goto") past a declaration with an 
>initializer unless that declaration is within a block nested within the
>current block.  (This is according to Stroustrup, _The_C++_Programming_
>
>There are those of us who occassionally use "goto" for efficiency 
>reasons (or even to make the code clearer).  It seems awkward and
>error-prone to me to have to consciously avoid jumping over declarations
>with initializers each time one uses a "goto", and to have to check
>that each declaration with an initializer is not in a code segment which 
>can possibly be skipped over by a "goto".  Such awkwardness does not
>lend itself to making code more maintainable.
[text deleted]

I hope this isn't starting a goto debate, but...
If the program is jumping into the middle of code that has variables (even if
they are not used) active that have not been initialized, the program is
_already_ not very maintainable (IMHO).  Don't get me wrong, I'm not an anti-
goto fanatic.  I am using them in a part of my code (at least until C++ gets
exception handling) because a non-goto version of the function would
look like a hack.  I have found the opposite to be true: localizing the
scope and delaying the definition of a local variable makes the code much
more maintainable.  The reason is, if I'm goto'ing _back_ in the code, it
destroys any variables decalared after the label I'm jumping to.  This
way, I don't have any old stuff hanging around.  If I jump
forward, I don't want to jump somewhere unless all active variables
at that place have been initialized.

Basicly, I believe if goto's are being used to improve program clarity,
delaying local variables declaration until point of use (which may be
necessary if they are being initialized) and localizing the scope of
variables as much as possible make the use of goto's safer and more
understandable to a person reading your code.  Besides, the argument
that "it makes a program with goto's hard to maintain", seems a little
like an oxymoron or something.

>of an uninitialized variable.  However, compilers can easily detect 
>instances of the use of uninitialized variables, while detecting the "goto" 
>error requires a more extensive analysis of the code's flow-of-control.

I'm not too sure what you're saying here...  Compilers already give an 
error if you goto past an object declaration.  I don't really understand 
why it's easier to detect uninitialized variables as opposed to skipping
variable declarations.  Let me know if I misinterpreted what you said.

PS: I was really thrilled when I discovered C++ goto's take care of calling 
destructors.  setjmp/longjmp don't, do they?  Anybody know when exception
handling and templates will be implemented (esp. on PC's)?  Will the
ANSI C++ standard have them?  Finally, does everybody know about comp.std.c++?
It's really quiet.

--Jamshid Afshar
--jamshid@ccwf.cc.utexas.edu

roger@procase.UUCP (Roger H. Scott) (08/22/90)

In article <2161@runxtsa.runx.oz.au> edward@runxtsa.runx.oz.au (Edward Birch) writes:
>A friend of mine works with a large organization where they have defined a
>standard that "variables must be declared where first used".
>
>I think that this is an absolutely insane standard for the following reasons:
>
>	o The declarations clutter the algorithm. 
This sounds like a completely subjective, personal opinion.  Is it intended
to be anything more?

>	o Most C and C++ programmers are used to seeing variables declared
>	  in one place. I believe that changing this will only add to
>	  maintenance costs and development time.
>	  C has had the ability to declare variables at the start of each
>	  block. How often is it used ? Why isn't it used ?
Who cares what "most C programmers" are used to?  Most C programmers are
used to slowly producing large volumes of unmaintainable code.  As far as
your "belief", again I ask if this is meant to be anything more than a
subjective personal opinion?  Could you share your reasononing with us?

>	o I have found that declaring variables where they are first used
>	  significantly adds to the development time of code. With little
>	  benefit to the over all presentation of the code.
Have you really done a controlled experiment where the only significant
difference in coding technique pertained to location of declarations?

>	o I also find that declaring variables at the start of functions
>	  in one spot to significantly adds to the readability of the code.
>
>I would be extremely interested in feedback.

It seems that you must be more interested in "what identifiers are declared
within a function" than in "what is the actual lifetime and usage of each
identifier".  I, for one, and *much* more interested in the latter than the
former.  Generally speaking, I consider an uninitialized variable declaration
to be distracting and counter-useful.  It is often the case that the uses of
any given variable within a function are all relatively close together,
although they may be relatively far from the "top" of the function.  In these
cases I definitely find it easier to write, understand, and maintain code
that declares the variables where they are first used.  I will go one step
further in this direction and say that I wouldn't mind the ability to
un-declare a variable after I am "done" with it so that someone else (or me)
looking at the code later doesn't have to scan down to the end of the scope
to make sure there isn't some other, later use being made of this oh-so-local
variable.

roger@procase.UUCP (Roger H. Scott) (08/22/90)

In article <1990Aug13.182226.24141@alias.uucp> bmcphers@alias.UUCP (Brent McPherson) writes:
>...
>Finally, common sense should prevail. If a variable is first assigned a value
>within a loop it should be declared outside the loop just in case the compiler
>decides to create the variable on the stack for each loop iteration.
If your compiler is really dumb enough to do that for an ordinary C-sort of
variable you need to get a new compiler.  The only case where I can imagine
that such a thing would be worth restructuring my code over is declarations
of automatic objects with constructors and/or destructors - it is unfortunate
that C++ compilers won't be smart enough to optimize such things in the
forseeable future.

purtill@morley.rutgers.edu (Mark Purtill) (08/24/90)

roger@procase.UUCP (Roger H. Scott) writes:
>I will go one step
>further in this direction and say that I wouldn't mind the ability to
>un-declare a variable after I am "done" with it so that someone else (or me)
>looking at the code later doesn't have to scan down to the end of the scope
>to make sure there isn't some other, later use being made of this oh-so-local
>variable.
	There is a way to do this; in fact, it was there in "plain" C;
just declare the variable in a local group:

    int 
function()
{
	/* ... */
	{
		int a_very_local_variable ;
		/* use of a_very_local_variable */
		}
	/* no uses of a_very_local_variable */
	}

This isn't eactly what you want (you can't overlap variables like:

	int a_very_local_variable ;
	...
	int another_very_local_variable ;
	...
	(undeclare a_very_local_variable) ;
	...
	(undeclare another_very_local_variable) ;
	...
) but it's still very useful sometimes when ones function is getting
rather long, but can't be split easily.

^.-.^ Mark Purtill        purtill@dimacs.rutgers.edu         (201)932-4580 (O)
((")) P.O. Box 1179, Rutgers Univ., Piscataway, NJ 08855     (201)220-6905 (H)
	 (Above information effective around 25 August 1990)

mjv@objects.mv.com (Michael J. Vilot) (08/24/90)

Roger Scott mentions:
> I wouldn't mind the ability to un-declare a variable after I am "done"
I use blocks to achieve this effect.  I also rely more on expressions and
less on explicit intermediate variables.

I sometimes use objects of classes that only provide constructors and
destructors.  I use them only for their side-effects.  Here's a simple
example:

	class Timer {
	  time_t start;
	public:
	  Timer();	// records start
	 ~Timer();	// computes elapsed, displays it on cerr
	};

	void f()
	{
	  // do some work

	  {
	    Timer t;

	    // do some timed work, and report the time at block exit
	  }

	  // etc.
	}

The Timer object `t' is only active in the inner block.  Of course, the
object is apparently never used, so I may get into trouble with those
building aggressively-optimizing compilers.

I hope such optimizations allow this use of constructor/destructor
side-effects.

--
Mike Vilot,  ObjectWare Inc, Nashua NH
mjv@objects.mv.com  (UUCP:  ...!decvax!zinn!objects!mjv)

sdm@cs.brown.edu (Scott Meyers) (08/24/90)

In article <883@zinn.MV.COM> mjv@objects.mv.com (Michael J. Vilot) writes:
| I sometimes use objects of classes that only provide constructors and
| destructors.  I use them only for their side-effects.  Here's a simple
| example:
...
| 	  {
| 	    Timer t;
| 
| 	    // do some timed work, and report the time at block exit
| 	  }
...
| The Timer object `t' is only active in the inner block.  Of course, the
| object is apparently never used, so I may get into trouble with those
| building aggressively-optimizing compilers.
| 
| I hope such optimizations allow this use of constructor/destructor
| side-effects.

This doesn't even always work in cfront 2.0, as I found out recently when I
tried implementing a class to automate routine tracing.

Scott

jimad@microsoft.UUCP (Jim ADCOCK) (08/28/90)

In article <41673@think.Think.COM> barmar@think.com (Barry Margolin) writes:
>In article <56642@microsoft.UUCP> jimad@microsoft.UUCP (Jim ADCOCK) writes:
>>It is certainly not the case that a thousand foos reside simultaneously
>>on the stack.  Rather, it is guaranteed that an object is destroyed as 
>>its constructor is jumped back over.  Thus, while conceptually there
>>are a 1000 foos, only one is in existance at any point in time, and they
>>all reside at the same location on the stack. 
>
>However, the compiler might decide to grow and shrink the stack frame each
>time the variable is created and destroyed.  Also, if the constructor
>and/or destructor do anything expensive (e.g. use "new" and "delete" on
>members of the object) this will be done each time through the loop, when
>it probably would be OK to reuse a single object.

Hm, do you know of any C++ compiler that actually grows and shrinks a
the stack within a routine? [in the absense if alloca()s]  A while back
I read a survey of C compilers that could identify no such compiler.
It turns out gotos in the language makes doing such problamatic.

Bottom line in any case:  if an object's construction and assignment
work more or less identically, you can just put the constructor outside
the loop, and assign inside the loop.  If an object's constructor and
assignment work considerably differently, you might need to move the
constructor inside the loop.

jimad@microsoft.UUCP (Jim ADCOCK) (08/28/90)

In article <883@zinn.MV.COM> mjv@objects.mv.com (Michael J. Vilot) writes:
|The Timer object `t' is only active in the inner block.  Of course, the
|object is apparently never used, so I may get into trouble with those
|building aggressively-optimizing compilers.
|
|I hope such optimizations allow this use of constructor/destructor
|side-effects.

Yes, such usages of objects for the side effects of their constructors
and destructors is explicetly allowed in the language, and will not
be removed by compiler optimizations.  Other common examples are objects
that act as locks, and objects that print out debugging info as a side
effect of construction or destruction.

bright@Data-IO.COM (Walter Bright) (08/30/90)

In article <56953@microsoft.UUCP> jimad@microsoft.UUCP (Jim ADCOCK) writes:
<In article <41673@think.Think.COM> barmar@think.com (Barry Margolin) writes:
<<However, the compiler might decide to grow and shrink the stack frame each
<<time the variable is created and destroyed.
<Hm, do you know of any C++ compiler that actually grows and shrinks a
<the stack within a routine? [in the absense if alloca()s]  A while back
<I read a survey of C compilers that could identify no such compiler.

There *are*, however, compilers that allocate variables on top of each
other if their live ranges do not intersect. This has the same effect
as adjusting the stack.

	func()
	{	{ int i; .... }
		{ int j; .... }
	}

i and j's live ranges do not overlap, so they can (and do with some compilers)
share the same storage location.

<It turns out gotos in the language makes doing such problamatic.

True if you actually are adjusting the SP, but not in the above scheme.

jimad@microsoft.UUCP (Jim ADCOCK) (09/05/90)

In article <2675@dataio.Data-IO.COM| bright@Data-IO.COM (Walter Bright) writes:
|In article <56953@microsoft.UUCP> jimad@microsoft.UUCP (Jim ADCOCK) writes:
|<In article <41673@think.Think.COM> barmar@think.com (Barry Margolin) writes:
|<<However, the compiler might decide to grow and shrink the stack frame each
|<<time the variable is created and destroyed.
|<Hm, do you know of any C++ compiler that actually grows and shrinks a
|<the stack within a routine? [in the absense if alloca()s]  A while back
|<I read a survey of C compilers that could identify no such compiler.
|
|There *are*, however, compilers that allocate variables on top of each
|other if their live ranges do not intersect. This has the same effect
|as adjusting the stack.
|
|	func()
|	{	{ int i; .... }
|		{ int j; .... }
|	}
|
|i and j's live ranges do not overlap, so they can (and do with some compilers)
|share the same storage location.
|
|<It turns out gotos in the language makes doing such problamatic.
|
|True if you actually are adjusting the SP, but not in the above scheme.

Yes, but C++ defines that destruction of named objects be on exit from
scope [with few exceptions], thus greatly restricting a compilers from
performing these optimizations on other than primitives.  Temporary
objects would be fair game for these optimizations, though....

ark@alice.UUCP (Andrew Koenig) (09/05/90)

In article <57167@microsoft.UUCP>, jimad@microsoft.UUCP (Jim ADCOCK) writes:

> |	func()
> |	{	{ int i; .... }
> |		{ int j; .... }
> |	}

> |i and j's live ranges do not overlap, so they can (and do with some compilers)
> |share the same storage location.

> Yes, but C++ defines that destruction of named objects be on exit from
> scope [with few exceptions], thus greatly restricting a compilers from
> performing these optimizations on other than primitives.

But in this example, the scopes of `i' and `j' end at the
close braces at the end of their respective lines.

Therefore a C++ implementation is certainly entitled to let
`i' and `j' share storage, as long as it destroys `i' before
constructing `j.'
-- 
				--Andrew Koenig
				  ark@europa.att.com

bothner@sevenlayer.cs.wisc.edu (Per Bothner) (09/08/90)

jimad@microsoft.UUCP (Jim ADCOCK) writes:
>|	func()
>|	{	{ int i; .... }
>|		{ int j; .... }
>|	}
>|
>|i and j's live ranges do not overlap, so they can (and do with some
>|compilers) share the same storage location.
>
>Yes, but C++ defines that destruction of named objects be on exit from
>scope [with few exceptions], thus greatly restricting a compilers from
>performing these optimizations on other than primitives.

Huh? "On exit from scope" means "at the end of the block"
in this case, so there is no problem allocating i and j
to the same location, even if their class(es) have destructors.

Construction and destruction must by definition delimit an
object's live range. Two variables in the same function,
but defined in non-intersection blocks do not have overlapping
live ranges. And can therefore share storage locations.
-- 
	--Per Bothner
bothner@cs.wisc.edu Computer Sciences Dept, U. of Wisconsin-Madison

jimad@microsoft.UUCP (Jim ADCOCK) (09/12/90)

In article <11190@spool.cs.wisc.edu> bothner@sevenlayer.cs.wisc.edu (Per Bothner) writes:
|jimad@microsoft.UUCP (Jim ADCOCK) writes:
|>|	func()
|>|	{	{ int i; .... }
|>|		{ int j; .... }
|>|	}
|>|
|>|i and j's live ranges do not overlap, so they can (and do with some
|>|compilers) share the same storage location.
|>
|>Yes, but C++ defines that destruction of named objects be on exit from
|>scope [with few exceptions], thus greatly restricting a compilers from
|>performing these optimizations on other than primitives.
|
|Huh? "On exit from scope" means "at the end of the block"
|in this case, so there is no problem allocating i and j
|to the same location, even if their class(es) have destructors.
|
|Construction and destruction must by definition delimit an
|object's live range. Two variables in the same function,
|but defined in non-intersection blocks do not have overlapping
|live ranges. And can therefore share storage locations.

Sorry for the confusion.  I thought it was obvious that when I was talking
about constructors/destructors--that I couldn't be talking about the above "int"
examples.  [Ints, and other built-ins can use destructor syntax under 2.1+
compilers -- but those destructors do nothing, and so do not change 
traditional optimization issues]

Yes. two objects in two non-overlapping scopes in a routine are guaranteed 
to have only one in existance at any moment, allowing their space on the
stack to be shared.  My claim is simply that this is not common programming
practice.  Common practice is for most objects to be declared in the outer
-most scope of a function, where their destructors are not called until 
function exit.  Thus, the compiler doesn't get a chance to optimize based on
lifetime of most C++ objects.

I claim that optimizing based on the lifetime of objects in stack isn't a
big issue anyway.  The real issue is optimizing based on the lifetime of
objects in register.  Reusing a register saves time and code space.  
Reusing a stack slot only saves a little on the frame size.