Topic: Can I do this? (ctor, virt base)
Author: Alexandre Oliva <oliva@dcc.unicamp.br>
Date: 1997/02/12 Raw View
Fergus Henderson writes:
> (base class)
> A
> / \
> B C
> \ /
> D
> |
> E
> (most derived class)
The original post mentioned that all inheritance involved was virtual,
but Fergus removed that part, and this raised an issue in my
mind. Given the following constructor:
>> // This order SHOULD be correct, but appears to not
>> // be in MSVC++4.5/Borland5.0
>> D(void) : B(*(s_temp = new BState()),
>> C(*s_temp), A(*s_temp) {}
>> };
If the initializers are reordered to match the inheritance graph
structure, it would become:
D(void) : A(*s_temp), B(*(s_temp = new BState())), C(*s_temp) {}
Notice the used of an uninitialized s_temp when initializing A.
The standard says there are sequence points between the initializers,
so the compiler could not do:
D(void) : A(*(s_temp = new BState())), B(*s_temp), C(*s_temp) {}
Even if it could deduce that this was the actual intention of the
user.
Shouldn't the need of reordering initializers be an error (instead of
just an optional warning), when there are side-effects involved?
--
Alexandre Oliva
mailto:oliva@dcc.unicamp.br mailto:aoliva@acm.org
Universidade Estadual de Campinas, SP, Brasil
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: James Kanze <james-albert.kanze@vx.cit.alcatel.fr>
Date: 1997/02/13 Raw View
Alexandre Oliva <oliva@dcc.unicamp.br> writes:
|> Fergus Henderson writes:
|>
|> > (base class)
|> > A
|> > / \
|> > B C
|> > \ /
|> > D
|> > |
|> > E
|> > (most derived class)
|>
|> The original post mentioned that all inheritance involved was virtual,
|> but Fergus removed that part, and this raised an issue in my
|> mind. Given the following constructor:
|>
|> >> // This order SHOULD be correct, but appears to not
|> >> // be in MSVC++4.5/Borland5.0
|> >> D(void) : B(*(s_temp = new BState()),
|> >> C(*s_temp), A(*s_temp) {}
|> >> };
|>
|> If the initializers are reordered to match the inheritance graph
|> structure, it would become:
|>
|> D(void) : A(*s_temp), B(*(s_temp = new BState())), C(*s_temp) {}
|>
|> Notice the used of an uninitialized s_temp when initializing A.
|> The standard says there are sequence points between the initializers,
|> so the compiler could not do:
|>
|> D(void) : A(*(s_temp = new BState())), B(*s_temp), C(*s_temp) {}
|>
|> Even if it could deduce that this was the actual intention of the
|> user.
Well, it could hardly deduce that this was the actual intention, since
it is entirely possible that the programmer *wanted* to use the old
value of s_temp to initialize A.
It's probably also worth pointing out that the sequence points are a
recent addition to the compiler, so counting on them is probably not a
good idea in portable code.
|> Shouldn't the need of reordering initializers be an error (instead of
|> just an optional warning), when there are side-effects involved?
I'd have no problems with this, but since any good compiler will
generate the warning, it's not really a big point.
--
James Kanze home: kanze@gabi-soft.fr +33 (0)1 39 55 85 62
office: kanze@vx.cit.alcatel.fr +33 (0)1 69 63 14 54
GABI Software, Sarl., 22 rue Jacques-Lemercier, F-78000 Versailles France
-- Conseils en informatique industrielle --
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: fjh@murlibobo.cs.mu.OZ.AU (Fergus Henderson)
Date: 1997/02/13 Raw View
Alexandre Oliva <oliva@dcc.unicamp.br> writes:
>Shouldn't the need of reordering initializers be an error (instead of
>just an optional warning), when there are side-effects involved?
It's difficult for a compiler to know when side-effects will be involved.
It would be possible to require that the initializer order be always
be the same as the declaration order, but that would unfortunately
be a non-backwards-compatible change. The committee is not very keen
on breaking existing code, and thus it was left as a "quality of
implementation" issue.
--
Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3 | -- the last words of T. S. Garp.
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Stephen.Clamage@Eng.Sun.COM (Steve Clamage)
Date: 1997/02/13 Raw View
In article fsf@dcc.unicamp.br, Alexandre Oliva <oliva@dcc.unicamp.br> writes:
>
>Shouldn't the need of reordering initializers be an error (instead of
>just an optional warning), when there are side-effects involved?
Determining that side effects that make a difference are involved is
an intractable (I believe unsolveable) problem. The compiler would
have to make the pessimistic assumptions that any function call in
an initializer (including constructor invocations) and any modification
of any object other than the one being initialized causes an important
side effect. Example:
class A { ... A(int); };
class B { ... A a1, a2; B(int); };
B::B(int i) : a2(i), a1(i) { ... }
The B mem-initializer order would have to be an error, because
A::A(int) might have a side effect that affected subsequent
invocations.
IMHO, you might as well make the language rule that mem-initializers must
be written in correct initialization order. In practice it would usually
amount to the same thing.
---
Steve Clamage, stephen.clamage@eng.sun.com
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: fjh@murlibobo.cs.mu.OZ.AU (Fergus Henderson)
Date: 1997/02/11 Raw View
cbay@bamboo.verinet.com (Charlie Bay) writes:
>Can I do this? I'm assuming initialization of the
>base classes from first parent, most derived level
>to last parent, most derived level up to the
>base level. Should this work in a base/member
>initializer list?
The order of initialization of virtual base classes is specified in
12.6.1/5:
| 12.6.1 Explicit initialization [class.expl.init]
|
| 5 Initialization shall proceed in the following order:
|
| --First, and only for the constructor of the most derived class as
| described below, virtual base classes shall be initialized in the
| order they appear on a depth-first left-to-right traversal of the
| directed acyclic graph of base classes, where "left-to-right" is the
| order of appearance of the base class names in the derived class
| base-specifier-list.
Although "left-to-right" is explained clearly, it's not entirely clear
from the wording what "depth-first" means. However, I'm sure the
intent is that base classes be initialized before derived classes --
contrary to your assumption above.
>I have a hierarchy of classes, with virtual base classes.
>Imagine an identical hierarchy of "state" classes that
>mirrors this hierarchy (I'm tracking the state of the
>classes external to the classes themselves).
>
>Given: A <- B <- D <- E
> <- C <-
If you draw that as
(base class)
A
/ \
B C
\ /
D
|
E
(most derived class)
and take a depth-first left-to-right traversal, treating the most
derived class as the "shallow" end and the base class as the "deep"
end, the order you get is A, B, C, D, E.
> // This order SHOULD be correct, but appears to not
> // be in MSVC++4.5/Borland5.0
> D(void) : B(*(s_temp = new BState()),
> C(*s_temp), A(*s_temp) {}
>};
I think that `A' will be initialized first here.
D(void) : A(*(s_temp = new BState()),
B(*s_temp), C(*s_temp) {}
Incidentally, a good compiler should warn you if the member-initializers
are listed in a different order to the order that they will be executed
in. A good compiler is hard to find, though...
> E(void) : D(*(s_temp2 = new EState()),
> D(*s_temp2), C(*s_temp2), B(*s_temp2), A(*s_temp2) {}
Similarly, I think that should be
E(void) : A(*(s_temp2 = new EState()),
B(*s_temp2), C(*s_temp2), D(*s_temp2) {}
--
Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3 | -- the last words of T. S. Garp.
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: cbay@bamboo.verinet.com (Charlie Bay)
Date: 1997/02/12 Raw View
Fergus Henderson (fjh@murlibobo.cs.mu.OZ.AU) wrote:
: The order of initialization of virtual base classes is specified in
: 12.6.1/5:
<snip, 12.6.1>
: Although "left-to-right" is explained clearly, it's not entirely clear
: from the wording what "depth-first" means. However, I'm sure the
: intent is that base classes be initialized before derived classes --
: contrary to your assumption above.
Ahh, this makes sense. I understood "exeuction order",
(base to derived), but had thought "initialization order"
was the reverse (derived to base) so that the derived-most
initialization could "forward" its parameters to its
base/member initilization lists.
I still think this is true, but possibly NOT for virtual
base classes. Does this make sense?
We must specify the initialization of immediate base members,
AND of any virtual bases (whether or not immediate). Thus,
will only the MOST DERIVED initialization of A() be called,
and the A() initialization at all previous levels be ignored?
After all, we only have ONE virtual A() base to work with.
This is a very interesting aside, if true; it's exactly
what I wanted, but one might want to be wary:
"The base/member initialization is NEVER EXECUTED for
a virtual base class if the derived class in question is
subclassed."
In other words, for the following diagram, D's A()
initialization is NEVER called when instantiating an "E":
: (base class)
: A
: / \
: B C // A() never called when instantiating an E()?
: \ /
: D // A() never called when instantiating an E()?
: |
: E // A() ONLY CALLED HERE when instantiating an
// E()? A() params NOT forwarded to D()'s A()?
: (most derived class)
<snip>
: and take a depth-first left-to-right traversal, treating the most
: derived class as the "shallow" end and the base class as the "deep"
: end, the order you get is A, B, C, D, E.
<snip, should be:>
: E(void) : A(*(s_temp2 = new EState()),
: B(*s_temp2), C(*s_temp2), D(*s_temp2) {}
Thanks _very_ much here... I find it to be a contrast between
EXECUTION order (base to derived), and INITIALIZATION order
(which is always derived to base, unless we have a virtual
base, where it is base to derived. :-) This helps a lot.
Thanks!!
--charley
cbay@verinet.com
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]