static member object initialization

S

subramanian100in

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
 
J

Jonathan Lane

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.
 
V

Victor Bazarov

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
 
B

Barry

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.
 
V

Victor Bazarov

Barry said:
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
 
B

Barry

Victor said:
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
 
J

Jonathan Lane

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?
 
B

Barry

Jonathan said:
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.
 
V

Victor Bazarov

Jonathan said:
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
 
B

Barry

Jonathan said:
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.
 
B

Barry

Barry said:
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();"
 
W

werasm

Barry said:
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
 
B

Barry

werasm said:
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
:)
 
J

James Kanze

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).
 
J

James Kanze

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.
 
J

James Kanze

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.
 
J

Jonathan Lane

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() ) ;


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.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,575
Members
45,053
Latest member
billing-software

Latest Threads

Top