84422238   
   From: musiphil@bawi.org   
      
   On 2012-04-25 17:08, Gene Bushuyev wrote:   
   > On Apr 25, 12:10 pm, Seungbeom Kim wrote:   
   >>   
   >> For example,   
   >>   
   >> A::A(double x, double y)   
   >> {   
   >> double r = hypot(x, y);   
   >> this->x = x / r;   
   >> this->y = y / r;   
   >>   
   >> }   
   >>   
   >> In this example, 'hypot(x, y)' represents an expensive function call   
   >> whose return value is to be used in initializing subsequent members.   
   >>   
   >> Is there a good way to do the same with an initialization list?   
   >   
   > Yes, for example:   
   >   
   > A::A(double x, double y, double r = hypot(x, y))   
   > : x(x/r), y(y/r)   
   > {   
   > }   
      
   This change affects the function signature and the class interface.   
   In particular, in order to let the clients construct an A object with   
   only two arguments, the default argument declaration should be in the   
   definition of class A, i.e. usually in the header, which exposes the   
   implementation detail and necessitates including additional headers   
   ( in this example) from A.h, not from A.cpp.   
      
   > But I would also suggest that the constructor might not need to have   
   > the burden of doing those calculations in the first place, it's more   
   > common for a constructor to initialize its members directly from   
   > constructor parameters:   
   >   
   > A::A(double x, double y) : x(x), y(y) {}   
   >   
   > and make the caller responsible for providing the expected parameters:   
   >   
   > double r = hypot(x, y);   
   > A(x/r, y/r);   
      
   That's up to the designer of the class to decide, not some details of   
   the language syntax. The calculation may be a part of enforcing the   
   class invariant, which is obviously the job of the constructor(s).   
      
      
   I think this is a flaw in the language, though its effect may not be   
   that serious and you can often live with it. Whether you have an empty   
   body or a non-empty body for the constructor, it has a stack frame   
   on which any temporary objects can live, and nothing prevents you   
   from constructing some temporary objects there between constructing   
   members, except that the language doesn't have a syntax to allow it.   
   For example, the language could have allowed something like this:   
      
   struct A   
   {   
    double x, y;   
    A(double x, double y) :   
    double r(hypot(x, y)), // a temporary object   
    x(x / r),   
    y(y / r)   
    { }   
   };   
      
   ( This hypothetical syntax is a bit confusing here as the use of ','   
    between the objects makes them look like an init-declarator-list   
    corresponding to a single decl-specifier-seq. Things would have been   
    better if we used ';' instead:   
      
    struct A   
    {   
    double x, y;   
    A(double x, double y) :   
    double r(hypot(x, y));   
    x(x / r);   
    y(y / r);   
    { }   
    };   
      
    This would have also solved the aesthetic/editorial problem of having   
    to omit the comma after the last member or maintaining the commas as   
    you add or delete members. -- I digress too much here. )   
      
   --   
   Seungbeom Kim   
      
      
    [ See http://www.gotw.ca/resources/clcm.htm for info about ]   
    [ comp.lang.c++.moderated. First time posters: Do this! ]   
      
   --- SoupGate-Win32 v1.05   
    * Origin: you cannot sedate... all the things you hate (1:229/2)   
|