static member object initialization

Discussion in 'C++' started by subramanian100in@yahoo.com, India, Sep 25, 2007.

  1. , India

    , India Guest

    Consider the following program:

    #include <iostream>

    using namespace std;

    class Test
    {
    static Test t;
    static Test init_Test( ) { return t; }
    Test(const Test & rhs) { cout << "copy ctor" << endl; }
    };

    Test Test::t = init_Test( );

    int main()
    {
    return 0;
    }

    This program compiles fine under both g++ and VC++2005 Express Edition
    and both produce the following same output
    copy ctor

    However consider the statement
    Test Test::t = init_Test( );
    Here init_Test( ) is called which returns the static member object
    under construction which is 't'. I do not understand how we can
    return an object which is still under construction.
    How is it accepted by the compiler ?

    Kindly explain

    Thanks
    V.Subramanian
    , India, Sep 25, 2007
    #1
    1. Advertising

  2. Try putting in a default constructor that writes some output. I think
    that will show you what's going on. Also, you're not returning t
    you're returning a copy of t.

    On Sep 25, 12:47 pm, ", India"
    <> wrote:
    > Consider the following program:
    >
    > #include <iostream>
    >
    > using namespace std;
    >
    > class Test
    > {
    > static Test t;
    > static Test init_Test( ) { return t; }
    > Test(const Test & rhs) { cout << "copy ctor" << endl; }
    >
    > };
    >
    > Test Test::t = init_Test( );
    >
    > int main()
    > {
    > return 0;
    >
    > }
    >
    > This program compiles fine under both g++ and VC++2005 Express Edition
    > and both produce the following same output
    > copy ctor
    >
    > However consider the statement
    > Test Test::t = init_Test( );
    > Here init_Test( ) is called which returns the static member object
    > under construction which is 't'. I do not understand how we can
    > return an object which is still under construction.
    > How is it accepted by the compiler ?
    >
    > Kindly explain
    >
    > Thanks
    > V.Subramanian
    Jonathan Lane, Sep 25, 2007
    #2
    1. Advertising

  3. wrote:
    > Consider the following program:
    >
    > #include <iostream>
    >
    > using namespace std;
    >
    > class Test
    > {
    > static Test t;
    > static Test init_Test( ) { return t; }
    > Test(const Test & rhs) { cout << "copy ctor" << endl; }
    > };
    >
    > Test Test::t = init_Test( );
    >
    > int main()
    > {
    > return 0;
    > }
    >
    > This program compiles fine under both g++ and VC++2005 Express Edition
    > and both produce the following same output
    > copy ctor
    >
    > However consider the statement
    > Test Test::t = init_Test( );
    > Here init_Test( ) is called which returns the static member object
    > under construction which is 't'. I do not understand how we can
    > return an object which is still under construction.
    > How is it accepted by the compiler ?


    How should the compiler be able to catch your *logical* errors? The
    compiler is not obligated to tell you your logic is incorrect. Or
    that you have a chicken and egg problem. The compiler just checks
    the syntax and types. Your code has undefined behaviour since it
    makes an attempt to use an uninitialised object. The same thing as
    here:

    int &r = r;

    I think the compiler is not required to find and flag all instances of
    undefined behaviour in your code.

    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, Sep 25, 2007
    #3
  4. , India

    Barry Guest

    , India wrote:
    > Consider the following program:
    >
    > #include <iostream>
    >
    > using namespace std;
    >
    > class Test
    > {
    > static Test t;
    > static Test init_Test( ) { return t; }
    > Test(const Test & rhs) { cout << "copy ctor" << endl; }
    > };
    >
    > Test Test::t = init_Test( );
    >
    > int main()
    > {
    > return 0;
    > }
    >
    > This program compiles fine under both g++ and VC++2005 Express Edition
    > and both produce the following same output
    > copy ctor
    >
    > However consider the statement
    > Test Test::t = init_Test( );
    > Here init_Test( ) is called which returns the static member object
    > under construction which is 't'. I do not understand how we can
    > return an object which is still under construction.
    > How is it accepted by the compiler ?
    >


    This is stunning, and even puzzling that "init_Test()' compiles, which
    should be Test::init_Test(); to be well-formed, I think

    Comeau online also accepts all the cases.
    Waiting guru for explanation.


    --
    Thanks
    Barry
    Barry, Sep 25, 2007
    #4
  5. Barry wrote:
    > , India wrote:
    >> Consider the following program:
    >>
    >> #include <iostream>
    >>
    >> using namespace std;
    >>
    >> class Test
    >> {
    >> static Test t;
    >> static Test init_Test( ) { return t; }
    >> Test(const Test & rhs) { cout << "copy ctor" << endl; }
    >> };
    >>
    >> Test Test::t = init_Test( );
    >>
    >> int main()
    >> {
    >> return 0;
    >> }
    >>
    >> This program compiles fine under both g++ and VC++2005 Express
    >> Edition and both produce the following same output
    >> copy ctor
    >>
    >> However consider the statement
    >> Test Test::t = init_Test( );
    >> Here init_Test( ) is called which returns the static member object
    >> under construction which is 't'. I do not understand how we can
    >> return an object which is still under construction.
    >> How is it accepted by the compiler ?
    >>

    >
    > This is stunning, and even puzzling that "init_Test()' compiles, which
    > should be Test::init_Test(); to be well-formed, I think
    >
    > Comeau online also accepts all the cases.
    > Waiting guru for explanation.


    Since you're defining 't' that is declared inside 'Test', 'Test' scope
    is also looked up. I am sure you can find it somewhere in subclause
    3.4 (name lookup).

    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, Sep 25, 2007
    #5
  6. , India

    Barry Guest

    Victor Bazarov wrote:
    > wrote:
    >> Consider the following program:
    >>
    >> #include <iostream>
    >>
    >> using namespace std;
    >>
    >> class Test
    >> {
    >> static Test t;
    >> static Test init_Test( ) { return t; }
    >> Test(const Test & rhs) { cout << "copy ctor" << endl; }
    >> };
    >>
    >> Test Test::t = init_Test( );
    >>
    >> int main()
    >> {
    >> return 0;
    >> }
    >>
    >> This program compiles fine under both g++ and VC++2005 Express Edition
    >> and both produce the following same output
    >> copy ctor
    >>
    >> However consider the statement
    >> Test Test::t = init_Test( );
    >> Here init_Test( ) is called which returns the static member object
    >> under construction which is 't'. I do not understand how we can
    >> return an object which is still under construction.
    >> How is it accepted by the compiler ?

    >
    > How should the compiler be able to catch your *logical* errors? The
    > compiler is not obligated to tell you your logic is incorrect. Or
    > that you have a chicken and egg problem. The compiler just checks
    > the syntax and types. Your code has undefined behaviour since it
    > makes an attempt to use an uninitialised object. The same thing as
    > here:
    >
    > int &r = r;
    >
    > I think the compiler is not required to find and flag all instances of
    > undefined behaviour in your code.
    >



    Well, the code from the OP, do have the "chicken and egg" problem, while
    this one does not:

    class A
    {
    static A a;
    static A Init() { return A(); }
    A() {}
    };

    A A::a = A::Init();
    // or even
    //A A::a = Init();

    int main()
    {
    }

    the code above compiles with Comeau online


    --
    Thanks
    Barry
    Barry, Sep 25, 2007
    #6
  7. On Sep 25, 2:02 pm, Barry <> wrote:
    > Victor Bazarov wrote:
    > > wrote:
    > >> Consider the following program:

    >
    > >> #include <iostream>

    >
    > >> using namespace std;

    >
    > >> class Test
    > >> {
    > >> static Test t;
    > >> static Test init_Test( ) { return t; }
    > >> Test(const Test & rhs) { cout << "copy ctor" << endl; }
    > >> };

    >
    > >> Test Test::t = init_Test( );

    >
    > >> int main()
    > >> {
    > >> return 0;
    > >> }

    >
    > >> This program compiles fine under both g++ and VC++2005 Express Edition
    > >> and both produce the following same output
    > >> copy ctor

    >
    > >> However consider the statement
    > >> Test Test::t = init_Test( );


    I would think that:
    Test Test::t <- this part runs the default ctor
    = init_Test() <- this part then calls operator=() on the newly
    constructed Test object. init_Test then returns t by value so you end
    up with a statement like:
    Test Test::t = Test(Test::t);
    Or am I missing the point here?
    Jonathan Lane, Sep 25, 2007
    #7
  8. , India

    Barry Guest

    Jonathan Lane wrote:
    > On Sep 25, 2:02 pm, Barry <> wrote:
    >> Victor Bazarov wrote:
    >>> wrote:
    >>>> Consider the following program:
    >>>> #include <iostream>
    >>>> using namespace std;
    >>>> class Test
    >>>> {
    >>>> static Test t;
    >>>> static Test init_Test( ) { return t; }
    >>>> Test(const Test & rhs) { cout << "copy ctor" << endl; }
    >>>> };
    >>>> Test Test::t = init_Test( );
    >>>> int main()
    >>>> {
    >>>> return 0;
    >>>> }
    >>>> This program compiles fine under both g++ and VC++2005 Express Edition
    >>>> and both produce the following same output
    >>>> copy ctor
    >>>> However consider the statement
    >>>> Test Test::t = init_Test( );

    >
    > I would think that:
    > Test Test::t <- this part runs the default ctor
    > = init_Test() <- this part then calls operator=() on the newly
    > constructed Test object. init_Test then returns t by value so you end
    > up with a statement like:
    > Test Test::t = Test(Test::t);
    > Or am I missing the point here?
    >


    My point is that whichever "Init()" or "A::Init()" is private member
    function, why access control does not apply here.

    --
    Thanks
    Barry
    Barry, Sep 25, 2007
    #8
  9. Jonathan Lane wrote:
    > On Sep 25, 2:02 pm, Barry <> wrote:
    >> Victor Bazarov wrote:
    >>> wrote:
    >>>> Consider the following program:

    >>
    >>>> #include <iostream>

    >>
    >>>> using namespace std;

    >>
    >>>> class Test
    >>>> {
    >>>> static Test t;
    >>>> static Test init_Test( ) { return t; }
    >>>> Test(const Test & rhs) { cout << "copy ctor" << endl; }
    >>>> };

    >>
    >>>> Test Test::t = init_Test( );

    >>
    >>>> int main()
    >>>> {
    >>>> return 0;
    >>>> }

    >>
    >>>> This program compiles fine under both g++ and VC++2005 Express
    >>>> Edition and both produce the following same output
    >>>> copy ctor

    >>
    >>>> However consider the statement
    >>>> Test Test::t = init_Test( );

    >
    > I would think that:
    > Test Test::t <- this part runs the default ctor
    > = init_Test() <- this part then calls operator=() on the newly
    > constructed Test object. init_Test then returns t by value so you end
    > up with a statement like:
    > Test Test::t = Test(Test::t);
    > Or am I missing the point here?


    Not only you're missing the point. You're also missing the fact that
    'init_Test' is a function and not an object. And you're also missing
    the fact that the statement

    Blah Blah::blah = blahblah();

    has no default constructor involved at all. It's called "copy-
    initialisation" and relates to copy construction. 'blahblah' would
    return a temporary (whatever way is used to construct it), and then
    the 'blah' object is copy-constructed from that temporary.

    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, Sep 25, 2007
    #9
  10. , India

    Barry Guest

    Jonathan Lane wrote:
    > On Sep 25, 2:02 pm, Barry <> wrote:
    >> Victor Bazarov wrote:
    >>> wrote:
    >>>> Consider the following program:
    >>>> #include <iostream>
    >>>> using namespace std;
    >>>> class Test
    >>>> {
    >>>> static Test t;
    >>>> static Test init_Test( ) { return t; }
    >>>> Test(const Test & rhs) { cout << "copy ctor" << endl; }
    >>>> };
    >>>> Test Test::t = init_Test( );
    >>>> int main()
    >>>> {
    >>>> return 0;
    >>>> }
    >>>> This program compiles fine under both g++ and VC++2005 Express Edition
    >>>> and both produce the following same output
    >>>> copy ctor
    >>>> However consider the statement
    >>>> Test Test::t = init_Test( );

    >
    > I would think that:
    > Test Test::t <- this part runs the default ctor
    > = init_Test() <- this part then calls operator=() on the newly
    > constructed Test object. init_Test then returns t by value so you end
    > up with a statement like:
    > Test Test::t = Test(Test::t);
    > Or am I missing the point here?
    >

    class A
    {
    static A a;
    static int i;

    static A Init() { return A(); }
    static int GetInt() {return 10;}

    A() {}
    };

    A A::a = A::Init();
    int A::i = A::GetInt();

    int main()
    {
    }

    well, I think I got a point,

    the initialization of static member data(no matter private/public), the
    initialization statement creates a scope, in this special scope, all
    member functions can be called.
    I don't know whether Victor meant this else thread.

    But if we initiate a global object of A like this:

    A a1 = A::Init();

    No way, A::Init() is private.

    --
    Thanks
    Barry
    Barry, Sep 25, 2007
    #10
  11. , India

    Barry Guest

    Barry wrote:
    > Jonathan Lane wrote:
    >> On Sep 25, 2:02 pm, Barry <> wrote:
    >>> Victor Bazarov wrote:
    >>>> wrote:
    >>>>> Consider the following program:
    >>>>> #include <iostream>
    >>>>> using namespace std;
    >>>>> class Test
    >>>>> {
    >>>>> static Test t;
    >>>>> static Test init_Test( ) { return t; }
    >>>>> Test(const Test & rhs) { cout << "copy ctor" << endl; }
    >>>>> };
    >>>>> Test Test::t = init_Test( );
    >>>>> int main()
    >>>>> {
    >>>>> return 0;
    >>>>> }
    >>>>> This program compiles fine under both g++ and VC++2005 Express Edition
    >>>>> and both produce the following same output
    >>>>> copy ctor
    >>>>> However consider the statement
    >>>>> Test Test::t = init_Test( );

    >>
    >> I would think that:
    >> Test Test::t <- this part runs the default ctor
    >> = init_Test() <- this part then calls operator=() on the newly
    >> constructed Test object. init_Test then returns t by value so you end
    >> up with a statement like:
    >> Test Test::t = Test(Test::t);
    >> Or am I missing the point here?
    >>

    > class A
    > {
    > static A a;
    > static int i;
    >
    > static A Init() { return A(); }
    > static int GetInt() {return 10;}
    >
    > A() {}
    > };
    >
    > A A::a = A::Init();
    > int A::i = A::GetInt();
    >
    > int main()
    > {
    > }
    >
    > well, I think I got a point,
    >
    > the initialization of static member data(no matter private/public), the
    > initialization statement creates a scope, in this special scope, all
    > member functions can be called.


    And this also explains that "A::Init();" can be replaced with "Init();"


    --
    Thanks
    Barry
    Barry, Sep 25, 2007
    #11
  12. , India

    werasm Guest

    Barry wrote:

    > Comeau online also accepts all the cases.
    > Waiting guru for explanation.


    Hey, no guru, but consider this little piece that
    also compiles (and should)
    :
    class A
    {
    static A a;
    A() {}
    };

    A A::a; //The same as A A::a = A();
    int main(){}

    The code above calls a constructor that's also
    private. Why should it not be able to call a
    static member function for the same reason?

    I suppose c++98, Par 3.4.1:12 could be it:

    A name used in the definition of a static data member
    of class X (...) is looked up as if the name was used in
    a member function of X. Boy did they think of <almost>
    everything :).

    Regards,

    Werner







    >
    >
    > --
    > Thanks
    > Barry
    werasm, Sep 25, 2007
    #12
  13. , India

    Barry Guest

    werasm wrote:
    > Barry wrote:
    >
    >> Comeau online also accepts all the cases.
    >> Waiting guru for explanation.

    >
    > Hey, no guru, but consider this little piece that
    > also compiles (and should)
    > :
    > class A
    > {
    > static A a;
    > A() {}
    > };
    >
    > A A::a; //The same as A A::a = A();
    > int main(){}
    >
    > The code above calls a constructor that's also
    > private. Why should it not be able to call a
    > static member function for the same reason?
    >
    > I suppose c++98, Par 3.4.1:12 could be it:
    >
    > A name used in the definition of a static data member
    > of class X (...) is looked up as if the name was used in
    > a member function of X. Boy did they think of <almost>
    > everything :).
    >


    Well, no need to compare with Bjarne, or ... to be guru. :)
    Actually, I shouldn't post the word, it's like "an very simple question"
    -- it hurts if the readers don't even know that issue.Putting "guru
    help" is likely to drive some people away
    :)


    --
    Thanks
    Barry
    Barry, Sep 25, 2007
    #13
  14. , India

    James Kanze Guest

    On Sep 25, 1:47 pm, ", India"
    <> wrote:
    > Consider the following program:


    > #include <iostream>


    > using namespace std;


    > class Test
    > {
    > static Test t;
    > static Test init_Test( ) { return t; }
    > Test(const Test & rhs) { cout << "copy ctor" << endl; }
    > };


    > Test Test::t = init_Test( );


    > int main()
    > {
    > return 0;
    > }


    > This program compiles fine under both g++ and VC++2005 Express
    > Edition and both produce the following same output
    > copy ctor


    Which doesn't really surprise me, knowing roughly what the
    compilers will generate.

    > However consider the statement
    > Test Test::t = init_Test( );
    > Here init_Test( ) is called which returns the static member object
    > under construction which is 't'. I do not understand how we can
    > return an object which is still under construction.


    You can't. It's undefined behavior.

    > How is it accepted by the compiler ?


    It's accepted by the compiler because the compiler is not
    required to diagnose the error. It's accepted, in fact, because
    the C++ is designed to allow separate compilation. There's
    nothing in the line you cite which causes problems per se, given
    that the compiler doesn't know what's in init_Test at that
    point. (init_Test could return a local static, or even a newly
    constructed object each time.) And there's nothing which causes
    a problem per se in init_Test, since most uses of it would be
    OK. It's only the combination of the two (this particular
    implementation of init_Test(), used in this particular context)
    which causes problems, and the language specification is
    carefully designed so that the compiler is never required to
    look into a function which is being called.

    In practice, you're code works because the copy constructor
    doesn't actually use the object it's copying. If it did, it
    would find it uninitialized (or rather, zero initialized, since
    this is a static object).

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, Sep 26, 2007
    #14
  15. , India

    James Kanze Guest

    On Sep 25, 3:36 pm, Jonathan Lane <>
    wrote:
    > On Sep 25, 2:02 pm, Barry <> wrote:
    > > Victor Bazarov wrote:
    > > > wrote:
    > > >> Consider the following program:


    > > >> #include <iostream>


    > > >> using namespace std;


    > > >> class Test
    > > >> {
    > > >> static Test t;
    > > >> static Test init_Test( ) { return t; }
    > > >> Test(const Test & rhs) { cout << "copy ctor" << endl; }
    > > >> };


    > > >> Test Test::t = init_Test( );


    > > >> int main()
    > > >> {
    > > >> return 0;
    > > >> }


    > > >> This program compiles fine under both g++ and VC++2005 Express Edition
    > > >> and both produce the following same output
    > > >> copy ctor


    > > >> However consider the statement
    > > >> Test Test::t = init_Test( );


    > I would think that:
    > Test Test::t <- this part runs the default ctor
    > = init_Test() <- this part then calls operator=() on the newly
    > constructed Test object.


    You would think wrong. There's no assignment here. We have a
    case of a punctuation symbol (the '=') which has two very
    different meanings. In an expression, it means assignment, but
    the expression here doesn't begin until after the '=' sign, and
    in a declaration, the '=' sign is used to specify copy
    initialization (which is the same as value initialization when
    the initialization expression has the same type as the object
    being initialized). The above statement has exactly the same
    meaning as:

    Test Test::t( init_Test() ) ;

    > init_Test then returns t by value so you end
    > up with a statement like:
    > Test Test::t = Test(Test::t);
    > Or am I missing the point here?


    I think you've misunderstood the C++ definition syntax.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, Sep 26, 2007
    #15
  16. , India

    James Kanze Guest

    On Sep 25, 3:39 pm, Barry <> wrote:
    [...]
    > My point is that whichever "Init()" or "A::Init()" is private
    > member function, why access control does not apply here.


    Access control applies, but you're initializing a member
    variable, so you are logically within the class.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, Sep 26, 2007
    #16
  17. On Sep 26, 9:09 am, James Kanze <> wrote:
    > On Sep 25, 3:36 pm, Jonathan Lane <>
    > wrote:
    >
    >
    >
    > > On Sep 25, 2:02 pm, Barry <> wrote:
    > > > Victor Bazarov wrote:
    > > > > wrote:
    > > > >> Consider the following program:
    > > > >> #include <iostream>
    > > > >> using namespace std;
    > > > >> class Test
    > > > >> {
    > > > >> static Test t;
    > > > >> static Test init_Test( ) { return t; }
    > > > >> Test(const Test & rhs) { cout << "copy ctor" << endl; }
    > > > >> };
    > > > >> Test Test::t = init_Test( );
    > > > >> int main()
    > > > >> {
    > > > >> return 0;
    > > > >> }
    > > > >> This program compiles fine under both g++ and VC++2005 Express Edition
    > > > >> and both produce the following same output
    > > > >> copy ctor
    > > > >> However consider the statement
    > > > >> Test Test::t = init_Test( );

    > > I would think that:
    > > Test Test::t <- this part runs the default ctor
    > > = init_Test() <- this part then calls operator=() on the newly
    > > constructed Test object.

    >
    > You would think wrong. There's no assignment here. We have a
    > case of a punctuation symbol (the '=') which has two very
    > different meanings. In an expression, it means assignment, but
    > the expression here doesn't begin until after the '=' sign, and
    > in a declaration, the '=' sign is used to specify copy
    > initialization (which is the same as value initialization when
    > the initialization expression has the same type as the object
    > being initialized). The above statement has exactly the same
    > meaning as:
    >
    > Test Test::t( init_Test() ) ;
    >
    > > init_Test then returns t by value so you end
    > > up with a statement like:
    > > Test Test::t = Test(Test::t);
    > > Or am I missing the point here?

    >
    > I think you've misunderstood the C++ definition syntax.

    Indeed I did. I realized my error last night. I think I missed the
    point that it was a static and the statement was outside of the main
    in this case. Anyway, I see the point now. Thanks.
    Jonathan Lane, Sep 26, 2007
    #17
    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. Replies:
    3
    Views:
    832
    Peter_Julian
    Oct 10, 2005
  2. , India
    Replies:
    2
    Views:
    388
    Tadeusz B. Kopec
    Nov 13, 2007
  3. dolphin
    Replies:
    3
    Views:
    1,327
    Pete Becker
    Dec 5, 2007
  4. Angus
    Replies:
    1
    Views:
    2,609
  5. aaragon
    Replies:
    2
    Views:
    606
    James Kanze
    Nov 2, 2008
Loading...

Share This Page