Topic: Why not A::A(something) : A(other) {} ?


Author: maxtal@Physics.usyd.edu.au (John Max Skaller)
Date: 1995/08/15
Raw View
In article <DCwops.HEo@world.std.com>, Tom Breton <tob@world.std.com> wrote:
>vandevod@ro.cs.rpi.edu (David Vandevoorde) writes:
>> Except for the initializer-list, I don't see how factoring out the
>> common construction adds significant overhead:
>
>"Factoring out" is usually proposed as a work-around, but it's not
>really a solution. 0) It can't initialize reference or const members. 1)
>Conceptually, it's just wrong. A member function should do stuff after
>construction, not before construction. Construction should come from
>ctors.

Actually, ctors are "wrong" themselves. Typcially,
you want to compute several values and stuff them into members.
Just as you can initialise the stack frame of a function
in stages with loops and so-on between initialisations, so too
one would like to do this for objects.

You can do so -- but only by using assignments.

Hm. I wonder how many compilers can optimise
default initialisation followed by assignment to copy construction?
This should be possible for Standard Library classes like "string"
where the semantics are known.

--
JOHN (MAX) SKALLER,         INTERNET:maxtal@suphys.physics.su.oz.au
Maxtal Pty Ltd,
81A Glebe Point Rd, GLEBE   Mem: SA IT/9/22,SC22/WG21
NSW 2037, AUSTRALIA     Phone: 61-2-566-2189
---
[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]





Author: tob@world.std.com (Tom Breton)
Date: 1995/08/06
Raw View
vandevod@ro.cs.rpi.edu (David Vandevoorde) writes:
> Except for the initializer-list, I don't see how factoring out the
> common construction adds significant overhead:

"Factoring out" is usually proposed as a work-around, but it's not
really a solution. 0) It can't initialize reference or const members. 1)
Conceptually, it's just wrong. A member function should do stuff after
construction, not before construction. Construction should come from
ctors.

        Tom






Author: imp@village.org (Warner Losh)
Date: 1995/08/06
Raw View
In article <DCwops.HEo@world.std.com>, Tom Breton <tob@world.std.com> wrote:
>"Factoring out" is usually proposed as a work-around, but it's not
>really a solution. 0) It can't initialize reference or const members. 1)
>Conceptually, it's just wrong. A member function should do stuff after
>construction, not before construction. Construction should come from
>ctors.

While 0) is kinda true (you can initialize them before you call
construct()) 1) needn't be true.

We found, in the OI project, that often times you want to call member
functions from a constructor.  These usually set the values of
variables, and what not, but other times had side effects (and we
desired them to have side effects).  We also found that we needed to
have, for every class, two slightly different ctors (we were passing
RTTI-like pointers around before RTTI was part of the language).  We
had little to no problems initializing our classes with construct()
member function that was private.

The only snag we ever hit was that a certain compiler would issue
warnings incorrectly in the following case:

 class A {
 ...
 private:
  construct( int );
 ...
 };

 class B : public A {
 ...
 private:
  construct( int, int );
 ...
 };

it would say that B::construct(int, int) hides A::construct(int).
Since A::construct is private, it is irrelevant that B::construct
hides it.  Any objects derived from A could never access or call it,
only in A's member functions would it be accessible (and you want it
that way).  The compiler people pig-headedly wouldn't listen to us and
refused to even consider making the change, or adding some sort of
pragma that says "Damnit, we know that, don't tell us about it."

[[ The actual compiler also was buggy in when it would or wouldn't
   issue the warning, based on if the class had any virtual functions
   or not (but sometimes it would be silent, even with virtuals) ]]

Warner
--
Warner Losh  "VMS Forever"  home: imp@village.org
Cyberspace Development, Inc   work: imp@marketplace.com
Makers of TIA, The Internet Adapter.  http://marketplace.com/





Author: page@cat.rpi.edu (Lance Page)
Date: 1995/08/04
Raw View
I propose that a constructor for a class A be allowed to invoke another
constructor of A in place of its base class & member initializers.
e.g.:

class A {
  A(other);
  A(something) : A(other) {}
  ...
};

Motivation:
-----------
 ** Source code advantages:
 If there are key requirements for constructors of this class,
   (e.g. initializing some special pointers or references), it is tedious,
 error-prone and bulky to have to replicate these initializations in all
 the constructors.
 ** Object code size:  Assume the definition A::A(something) : A(other) {}
 If A::A(other) was of significant size and not inlined, then
 A::A(something), whether inline or not, could reuse this object code.
 ** Speed: Compare this to the technique by which multiple ctors share an init(..) method...
    -- The init() version calls separate construct(empty) and
initialize(as desired) methods for each *member* object, even if a single
construct(as desired) should suffice.  These unnecessary costs add up...
    -- If the init() method can be called at any time in an object's life,
then it may have to check the prior state of the object and "clean it up",
before initializing the object to a new value.  Thus, the member objects get
constructed(empty), tested, and then init'd(as desired), instead of
constructed(as desired).

Any one of these considerations can currently be worked around by careful
design, but the status quo forces an unnecessary trade-off between these
source code, object code size, and speed considerations.

Limitations:
-----------
 ** It makes sense to dictate that using this feature precludes
 using any other base class/ member initializers (i.e. before the '{')
 in this constructor.
 Reasons:
   (1) because the ctor being called by this ctor implicitly acts upon the
 entire object.
   (2) such a restriction conveniently avoids complicated "what about all
 these  combinations of initializers..." issues--  making this a feature
 that non-lawyers can understand.

Implementation:
---------------
 ** Seems obvious (to someone who has never implemented a compiler...)
 ** Normal declaration-order and inlining rules apply.

Prior discussion:
-----------------
  Extracted from Marshall P. Cline's C++ FAQ:
  >  Q18: How can I make a constructor call another constructor as a primitive?
  > No way.
  > [explanation that calling the ctor ends up ct'ing a secondary local object...]
  ...But there's no explanation why a mechanism to do "what is desired" is
provided.
  (And using the method I suggest, it is clear that you want to call
  the other ctor on "*this", not some secondary local object.)

  I'd be surprised if a proposal like this one hadn't been discussed
before--- it's simple, and the benefits are real.

Anyway... "why not?".

-Lance Page





Author: vandevod@ro.cs.rpi.edu (David Vandevoorde)
Date: 1995/08/04
Raw View
In article <3vtd09$83f@usenet.rpi.edu>, Lance Page <page@cat.rpi.edu> wrote:
>
>I propose that a constructor for a class A be allowed to invoke another
>constructor of A in place of its base class & member initializers.
>e.g.:
>
>class A {
>  A(other);
>  A(something) : A(other) {}
>  ...
>};
>
[...]
>Anyway... "why not?".
>
>-Lance Page

Except for the initializer-list, I don't see how factoring out the
common construction adds significant overhead:

 struct A {
     A("other"): "init_list" { ... construct(common); ... }
            A("something"): "init_list" { ... construct("common"); ... }
            // ...
        private:
            void construct("common") ...
            // ...
        };

The initializer list must be repeated, but I think that is rarely
a problem, is it?

 Daveed