A constructor calling another constructor (default constructor)?

Discussion in 'C++' started by Generic Usenet Account, Nov 27, 2007.

  1. I am having an argument with a colleague who insists that an
    overloaded constructor can call the default constructor using the
    initializer list syntax ---- something like this:

    class SomeClass
    {
    public:
    SomeClass()
    {
    std::cout << "This is the default constructor\n";
    }

    SomeClass(const string& str):SomeClass()
    {
    std::cout << "This is the overloaded constructor\n";
    }

    };

    I am convinced that is not possible ---- and our compiler also does
    not support it. Can someone point me to the correct portion of the C+
    + standard where I can find documentary proof to the contrary? I am
    finding 597 references to the word "constructor" in the standard :-(

    Thanks,
    Song
    Generic Usenet Account, Nov 27, 2007
    #1
    1. Advertising

  2. Generic Usenet Account wrote:
    > I am having an argument with a colleague who insists that an
    > overloaded constructor can call the default constructor using the
    > initializer list syntax ---- something like this:
    >
    > class SomeClass
    > {
    > public:
    > SomeClass()
    > {
    > std::cout << "This is the default constructor\n";
    > }
    >
    > SomeClass(const string& str):SomeClass()
    > {
    > std::cout << "This is the overloaded constructor\n";
    > }
    >
    > };
    >
    > I am convinced that is not possible ---- and our compiler also does
    > not support it. Can someone point me to the correct portion of the C+
    > + standard where I can find documentary proof to the contrary? I am
    > finding 597 references to the word "constructor" in the standard :-(


    In the current Standard it's not possible because "constructors do not
    have names and cannot be called". But in the future edition I believe
    there is a change that allows forwarding the control to different
    constructors, like you showed here. I'm too lazy to look up the doc
    number for that proposal.

    See [class.ctor]/2.

    In the proposed standard draft (n2315) I see this ([class.base.init]/2)
    <<
    A mem-initializer-list can delegate to another constructor of the
    constructor's class using any name that denotes the constructor's
    class itself. If a mem-initializer-id designates the constructor's
    class, it shall be the only mem-initializer; the constructor is
    a delegating constructor, and the constructor selected by the mem-
    initializer is the target constructor. The principal constructor is
    the first constructor invoked in the construction of an object
    (that is, not a target constructor for that object's construction).
    The target constructor is selected by overload resolution. Once the
    target constructor returns, the body of the delegating constructor
    is executed. If a constructor delegates to itself directly or
    indirectly, the program is ill-formed; no diagnostic is required.
    [ Example:
    struct C {
    C( int ) { } // 1: non-delegating constructor
    C(): C(42) { } // 2: delegates to 1
    C( char c ) : C(42.0) { } // 3: ill-formed due to recursion with 4
    C( double d ) : C('a') { } // 4: ill-formed due to recursion with 3
    };
    - end example]
    <<

    HTH

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
    Victor Bazarov, Nov 27, 2007
    #2
    1. Advertising

  3. * Victor Bazarov:
    > Generic Usenet Account wrote:
    >> I am having an argument with a colleague who insists that an
    >> overloaded constructor can call the default constructor using the
    >> initializer list syntax ---- something like this:
    >>
    >> class SomeClass
    >> {
    >> public:
    >> SomeClass()
    >> {
    >> std::cout << "This is the default constructor\n";
    >> }
    >>
    >> SomeClass(const string& str):SomeClass()
    >> {
    >> std::cout << "This is the overloaded constructor\n";
    >> }
    >>
    >> };
    >>
    >> I am convinced that is not possible ---- and our compiler also does
    >> not support it. Can someone point me to the correct portion of the C+
    >> + standard where I can find documentary proof to the contrary? I am
    >> finding 597 references to the word "constructor" in the standard :-(


    As Victor notes below it's part of C++0x but not of the current standard.

    For the current C++0x draft go to the committee pages, <url:
    http://www.open-std.org/jtc1/sc22/wg21/docs/projects#14882>.

    Keeping within the current language, you can use either an init member
    function (practically ugly and limited and unsafe) or derive from an
    articial base class (practically much better and general but offensive
    to design purists -- it's not mentioned in the FAQ).


    > In the current Standard it's not possible because "constructors do not
    > have names and cannot be called".


    Do not have names and so are not found during function name lookup.

    An overload set is formed nonetheless, and overload resolution performed
    for the call.


    > But in the future edition I believe
    > there is a change that allows forwarding the control to different
    > constructors, like you showed here. I'm too lazy to look up the doc
    > number for that proposal.
    >
    > See [class.ctor]/2.
    >
    > In the proposed standard draft (n2315) I see this ([class.base.init]/2)
    > <<
    > A mem-initializer-list can delegate to another constructor of the
    > constructor's class using any name that denotes the constructor's
    > class itself. If a mem-initializer-id designates the constructor's
    > class, it shall be the only mem-initializer; the constructor is
    > a delegating constructor, and the constructor selected by the mem-
    > initializer is the target constructor. The principal constructor is
    > the first constructor invoked in the construction of an object
    > (that is, not a target constructor for that object's construction).
    > The target constructor is selected by overload resolution. Once the
    > target constructor returns, the body of the delegating constructor
    > is executed. If a constructor delegates to itself directly or
    > indirectly, the program is ill-formed; no diagnostic is required.
    > [ Example:
    > struct C {
    > C( int ) { } // 1: non-delegating constructor
    > C(): C(42) { } // 2: delegates to 1
    > C( char c ) : C(42.0) { } // 3: ill-formed due to recursion with 4
    > C( double d ) : C('a') { } // 4: ill-formed due to recursion with 3
    > };
    > - end example]
    > <<


    Cheers,

    - Alf

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
    Alf P. Steinbach, Nov 27, 2007
    #3
  4. Generic Usenet Account

    Guest

    On Nov 27, 5:37 pm, "Victor Bazarov" <> wrote:
    > In the current Standard it's not possible because "constructors do not
    > have names and cannot be called". But in the future edition I believe
    > there is a change that allows forwarding the control to different
    > constructors, like you showed here. I'm too lazy to look up the doc
    > number for that proposal.



    You can hack it with placement new. Ugly but it works. And I can't
    really imagine why you wouldn't just move the default ctor's code into
    a common routine you could call from the others.


    #include <iostream>

    class SomeClass
    {
    public:
    SomeClass()
    {
    std::cout << "This is the default constructor\n";
    }

    SomeClass(int i)
    {
    std::cout << "This is the int constructor\n";
    }

    SomeClass(double d)
    {
    std::cout << "This is the double constructor\n";
    new(this) SomeClass; // Invoke default ctor
    }

    void * operator new(size_t, void *p) {return p;}

    };



    int main(void)
    {
    SomeClass sc;
    SomeClass sci(1);
    SomeClass scd(2.0);

    return 0;
    }
    , Nov 28, 2007
    #4
  5. * :
    > On Nov 27, 5:37 pm, "Victor Bazarov" <> wrote:
    >> In the current Standard it's not possible because "constructors do not
    >> have names and cannot be called". But in the future edition I believe
    >> there is a change that allows forwarding the control to different
    >> constructors, like you showed here. I'm too lazy to look up the doc
    >> number for that proposal.

    >
    >
    > You can hack it with placement new. Ugly but it works.


    Apart from the UB it imposes impractical requirements on derived classes.


    > And I can't
    > really imagine why you wouldn't just move the default ctor's code into
    > a common routine you could call from the others.


    One case is where a base class sub-object has no default constructor.

    Cheers, & hth.,

    - Alf


    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
    Alf P. Steinbach, Nov 28, 2007
    #5
  6. Generic Usenet Account

    Kaz Kylheku Guest

    On Nov 27, 3:28 pm, Generic Usenet Account <>
    wrote:
    > I am having an argument with a colleague who insists that an
    > overloaded constructor can call the default constructor using the
    > initializer list syntax ---- something like this:
    >
    > class SomeClass
    > {
    > public:
    > SomeClass()
    > {
    > std::cout << "This is the default constructor\n";
    > }
    >
    > SomeClass(const string& str):SomeClass()


    This is not well formed, because the ``mem-initializer-id'' names
    something which is not a member of the class, nor is a direct or
    indirect base class.

    > not support it. Can someone point me to the correct portion of the C+
    > + standard where I can find documentary proof to the contrary?


    12.6.2. This is where the ctor-initializer syntax is presented along
    with its semantics.

    Paragraph 2 introduces the explicit constraints on the names in a
    member initializer.
    Kaz Kylheku, Nov 28, 2007
    #6
  7. Generic Usenet Account

    Kaz Kylheku Guest

    On Nov 27, 3:28 pm, Generic Usenet Account <>
    wrote:
    > I am having an argument with a colleague who insists that an
    > overloaded constructor can call the default constructor using the
    > initializer list syntax ---- something like this:
    >
    > class SomeClass
    > {
    > public:
    > SomeClass()
    > {
    > std::cout << "This is the default constructor\n";
    > }
    >
    > SomeClass(const string& str):SomeClass()


    This is not well formed, because the ``mem-initializer-id'' names
    something which is not a nonstatic data member of the class, nor is a
    direct or virtual base of SomeClass.

    > not support it. Can someone point me to the correct portion of the C+
    > + standard where I can find documentary proof to the contrary?


    12.6.2. This is where the ctor-initializer syntax is presented along
    with its semantics.

    Paragraph 2 introduces the explicit constraints on the names in a
    member initializer.
    Kaz Kylheku, Nov 28, 2007
    #7
  8. Generic Usenet Account

    Guest

    On Nov 27, 6:40 pm, "Alf P. Steinbach" <> wrote:
    > * :
    >
    > > On Nov 27, 5:37 pm, "Victor Bazarov" <> wrote:
    > >> In the current Standard it's not possible because "constructors do not
    > >> have names and cannot be called". But in the future edition I believe
    > >> there is a change that allows forwarding the control to different
    > >> constructors, like you showed here. I'm too lazy to look up the doc
    > >> number for that proposal.

    >
    > > You can hack it with placement new. Ugly but it works.

    >
    > Apart from the UB it imposes impractical requirements on derived classes.



    What UB? I'm not saying there isn't, but I'm not seeing anything that
    would forbid this.
    , Nov 28, 2007
    #8
  9. wrote:
    > And I can't
    > really imagine why you wouldn't just move the default ctor's code into
    > a common routine you could call from the others.


    Because there may be member variables which cannot be initialized in a
    member function, only in the initializer list of a constructor?
    Juha Nieminen, Nov 28, 2007
    #9
  10. * :
    > On Nov 27, 6:40 pm, "Alf P. Steinbach" <> wrote:
    >> * :
    >>
    >>> On Nov 27, 5:37 pm, "Victor Bazarov" <> wrote:
    >>>> In the current Standard it's not possible because "constructors do not
    >>>> have names and cannot be called". But in the future edition I believe
    >>>> there is a change that allows forwarding the control to different
    >>>> constructors, like you showed here. I'm too lazy to look up the doc
    >>>> number for that proposal.
    >>> You can hack it with placement new. Ugly but it works.

    >> Apart from the UB it imposes impractical requirements on derived classes.

    >
    >
    > What UB? I'm not saying there isn't, but I'm not seeing anything that
    > would forbid this.


    UB appears when there is a base or member with non-trivial destructor
    /and/ the program "depends on the side effects produced by the
    destructor" per ยง3.8/4. Essentially because the standard guarantees
    that the destructor isn't called implicitly, so it isn't called. And
    since it's impossible to know about dependencies on side effects of
    destructors of objects of library classes, it's just plain general UB.

    Of course the fix for that UB is to introduce an explicit destructor
    call. Which also gets rid of possible memory leaks (e.g. from a
    std::string member whose destructor would otherwise not be called).

    But then there is a more subtle UB argument which would apply more
    generally (even for the case of an empty class such as the example code)
    namely that by completing execution of two constructors of class T for
    the same memory region, two objects have been created in the same memory
    region. And the argument has been put forward that this is illegal for
    non-POD classes, but I haven't seen this backed up by references to the
    standard. On the other hand, it's a practically important argument,
    because constructor calls are special and typically set up vtables and
    may have to keep track of where they're called from (in the case of
    virtual inheritance), and reconstructing the object under construction,
    even when remembering to first destroy it by using an explicit
    destructor call, very likely invalidates the compiler's assumptions.

    Cheers, & hth.,

    - Alf

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
    Alf P. Steinbach, Nov 28, 2007
    #10
  11. Generic Usenet Account

    Guest

    On Nov 27, 9:25 pm, "Alf P. Steinbach" <> wrote:
    > But then there is a more subtle UB argument which would apply more
    > generally (even for the case of an empty class such as the example code)
    > namely that by completing execution of two constructors of class T for
    > the same memory region, two objects have been created in the same memory
    > region. And the argument has been put forward that this is illegal for
    > non-POD classes, but I haven't seen this backed up by references to the
    > standard.



    I also started thinking about the non-POD member case after I wrote
    that. At the very least running the placement new hack would run the
    member constructors twice, which might be harmless in some cases, but
    certainly has the potential for odd results in others.
    , Nov 28, 2007
    #11
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Asfand Yar Qazi
    Replies:
    6
    Views:
    15,627
    jeffc
    May 17, 2004
  2. Dave Burns
    Replies:
    2
    Views:
    647
    Dave Burns
    Jan 12, 2007
  3. Neroku
    Replies:
    8
    Views:
    1,197
    Tor Iver Wilhelmsen
    Nov 18, 2006
  4. desktop
    Replies:
    2
    Views:
    458
    Victor Bazarov
    Jun 6, 2007
  5. Alf P. Steinbach
    Replies:
    4
    Views:
    410
    James Kanze
    Nov 30, 2007
Loading...

Share This Page