Re: Initialization and trivial constructors
dave@boostpro.com (Dave Abrahams) wrote (abridged):
They may be trying to say that:
Class::Class() : a(0), b(0), c(0), d(0) {
}
would be better written as:
Class::Class() {
a = 0;
b = 0;
c = 0;
d = 0;
}
The former may be more efficient if the members have code in their
constructors, but if they are just ints, then the efficiency will
be about the same. The latter version is arguably easier to read,
write and edit.
As soon as you put something in the constructor body, you've
introduced mutation, which makes code much harder to reason about.
Although that's a consideration, I don't think it's significant here. Obviously if
the members are const then we have to use an initialiser list. If we have the
option of using the constructor body, some mutation is inevitable.
It's a purely local matter, that only affects the few lines of code in the
constructor, which should be easy to reason about regardless. If the code does get
more complex, it will probably be too complex for initialiser lists.
[...] You've also introduced semantics that can't be automatically
reversed if there's an exception.
I don't follow this point. In the second example, how and why would you want to
reverse something like "a = 0;" when a is an int? Doesn't this issue only apply to
members whose constructor isn't trivial? If the constructor does nothing,
presumably the destructor does nothing too, else the class is probably unsafe
regardless.
Like the use of "hungarian notation", the policy makes the details
of code sensitive to the specific types used, rather than to the
concepts they model---should I really have to rewrite constructors
if I replace
typedef double fraction;
with
typedef boost::rational<long> fraction;
?
I agree the policy is over-stated as written. It shouldn't require code to be
rewritten.
Note the code will still work with the same semantics after such a change. There
will at most be a performance difference, but a good compiler will probably
optimise it away, and if not, the difference will probably be too small to measure.
Measure it, then optimise if the overhead is significant.
I've more often written constructors using initialiser lists and then later
unpicked it to use the constructor body, than vice versa.
and full of restrictions and special cases;
A list, please!
I've already mentioned them, but if you want it in list form:
o Order of evaluation may not be order written.
o Unable to add more code between initialisations (so it
doesn't scale).
o Unable to initialise arrays this way (prior to C++11).
o Exception handling has some weird syntax that I can't even
find online examples of.
o It's a different way of writing code.
By that last point, I mean the usual way of writing code is with statements, one
per line, terminated by a semi-colon. With initialiser lists we have instead
expressions separated by commas, that tend to all be put on the same line until it
doesn't fit and then it gets indented randomly. I've even seen people put the comma
at the start of the line. It's not just cosmetic. It means the code in the copy
constructor looks different to that in the assignment operator, or indeed any other
method.
they are part of what makes C++ hard.
Au contraire, they are part of what make C++ easy, if you know how
to use them and think about them.
I know how to use them and think about them. I am to some extent playing Devil's
Advocate here. Nevertheless, the points I'm making are valid.
-- Dave Harris, Nottingham, UK.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]