conversion constructor called twice - why?

Discussion in 'C++' started by Alexander Stippler, Oct 30, 2005.

  1. Given the following code snippet we get some unexpected behaviour:
    //--------------------------------------------------------------------
    #include <iostream>

    using namespace std;

    struct A
    {
    A() { cerr << "A()" << endl; }
    };

    struct C;

    struct B : public A
    {
    B();

    explicit
    B(const B &rhs);

    B(const A&rhs);

    C
    operator()(int from, int to);
    };

    struct C: public A
    {
    B r;

    operator const B &() const;
    };

    B::B() { cerr << "B()" << endl; }

    B::B(const B &rhs)
    { cerr << "B(const B &rhs)" << endl; }

    B::B(const A &rhs)
    { cerr << "B(const A &rhs)" << endl; }

    C
    B::eek:perator()(int from, int to) { return C(); }

    C::eek:perator const B &() const
    { cerr << "operator const B &() const" << endl;
    return r;
    }

    int main()
    {
    C c;
    B b = c; // conversion constructor called twice here - why??
    return 0;
    }
    //--------------------------------------------------------------------

    The conversion constructor B(const A &) is called twice when
    initializing object b. We would expect a call of
    C::eek:perator const B &() const
    and then one call of
    B::B(const B &).
    Alexander Stippler, Oct 30, 2005
    #1
    1. Advertising

  2. Alexander Stippler wrote:
    > struct B : public A
    > {
    > explicit
    > B(const B &rhs);
    >
    > B(const A&rhs);
    >
    > };


    > B b = c; // conversion constructor called twice here - why??


    > The conversion constructor B(const A &) is called twice when
    > initializing object b. We would expect a call of
    > C::eek:perator const B &() const
    > and then one call of
    > B::B(const B &).


    The call to B::B(const B&) is not happening because that copy constructor is explicit.

    Regarding calling this constructor twice - See 8.5/14 "Otherwise (i.e. for the remaining...".

    Since your copy constructor in B is explicit, so the compiler chooses another path, i.e.
    1. "c" is casted to A&
    2. a temporary of class B is created from the result via the "B(const A&)" constructor.
    3. your "b" is initialised with that temporary.

    --

    Valentin Samko - http://www.valentinsamko.com
    Valentin Samko, Oct 31, 2005
    #2
    1. Advertising

  3. Alexander Stippler

    Greg Guest

    Valentin Samko wrote:
    > Alexander Stippler wrote:
    > > struct B : public A
    > > {
    > > explicit
    > > B(const B &rhs);
    > >
    > > B(const A&rhs);
    > >
    > > };

    >
    > > B b = c; // conversion constructor called twice here - why??

    >
    > > The conversion constructor B(const A &) is called twice when
    > > initializing object b. We would expect a call of
    > > C::eek:perator const B &() const
    > > and then one call of
    > > B::B(const B &).

    >
    > The call to B::B(const B&) is not happening because that copy constructor is explicit.
    >
    > Regarding calling this constructor twice - See 8.5/14 "Otherwise (i.e. for the remaining...".
    >
    > Since your copy constructor in B is explicit, so the compiler chooses another path, i.e.
    > 1. "c" is casted to A&
    > 2. a temporary of class B is created from the result via the "B(const A&)" constructor.
    > 3. your "b" is initialised with that temporary.


    No, there is no temporary. Two user-defined conversions would be one
    more than is allowed. Besides, there is no need of a B temporary since
    B has a constructor that accepts an A object directly. So b is
    constructed from an A class object (namely, c).

    Greg
    Greg, Oct 31, 2005
    #3
  4. Greg wrote:
    > Valentin Samko wrote:
    >> Alexander Stippler wrote:
    >>> struct B : public A
    >>> {
    >>> explicit
    >>> B(const B &rhs);
    >>>
    >>> B(const A&rhs);
    >>>
    >>> };
    >>> B b = c; // conversion constructor called twice here - why??
    >>> The conversion constructor B(const A &) is called twice when
    >>> initializing object b. We would expect a call of
    >>> C::eek:perator const B &() const
    >>> and then one call of
    >>> B::B(const B &).

    >> The call to B::B(const B&) is not happening because that copy constructor is explicit.
    >>
    >> Regarding calling this constructor twice - See 8.5/14 "Otherwise (i.e. for the remaining...".
    >>
    >> Since your copy constructor in B is explicit, so the compiler chooses another path, i.e.
    >> 1. "c" is casted to A&
    >> 2. a temporary of class B is created from the result via the "B(const A&)" constructor.
    >> 3. your "b" is initialised with that temporary.

    >
    > No, there is no temporary. Two user-defined conversions would be one
    > more than is allowed. Besides, there is no need of a B temporary since
    > B has a constructor that accepts an A object directly. So b is
    > constructed from an A class object (namely, c).


    Please read 8.5/14. The right hand side has to be converted to the destination type (B)
    first. Only after the rhs is converted, compiler picks the most appropriate constructor.

    Besides, no used-defined conversions happen.

    --

    Valentin Samko - http://www.valentinsamko.com
    Valentin Samko, Oct 31, 2005
    #4
    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. Manuel Vázquez Acosta

    Global constructor called twice

    Manuel Vázquez Acosta, Jan 22, 2005, in forum: ASP .Net
    Replies:
    1
    Views:
    528
    Ryan Trudelle-Schwarz
    Jan 22, 2005
  2. Robert
    Replies:
    6
    Views:
    505
  3. Replies:
    10
    Views:
    547
    Dave Townsend
    Oct 2, 2005
  4. Mr. SweatyFinger
    Replies:
    2
    Views:
    1,679
    Smokey Grindel
    Dec 2, 2006
  5. TechCrazy
    Replies:
    5
    Views:
    388
    Karl Heinz Buchegger
    Jul 15, 2005
Loading...

Share This Page