What does the initialization of a reference object do?

Z

ziman137

Hi all,

The results from following codes got me a bit confused.

#include <stdio.h>
#include <iostream>

using namespace std;

struct A {

A () { cout << "A() ctor!" << endl; };

~A() { cout << "~A() dtor!" << endl; };

void foo () { printf("this=%p\n", this); };

int x, y;

};


main ()
{

A& a = a;
cout << "&a=" << &a << endl;
a.foo(); // is it legal here?
// a.x = 10; // illegal here
// a.y = 20;

A a1;
A& a2 = a1;
cout << "&a1=" << &a1 << endl;
cout << "a2."; a2.foo();

}

gcc version 3.2.2 20030222 (Red Hat Linux 3.2.2-5)
g++ -o foo foo.cpp
foo
&a=0x80488ce
this=0x80488ce
A() ctor!
&a1=0xbffff0d0
a2.this=0xbffff0d0
~A() dtor!

What does the initialization of a reference object do? Suppose the
initialization of reference is simply has its "this" pointer to the
target object. This does not call constructor, which is true. For
self-referenced "A& a = a", how can its "this" pointer be correctly
bound to member function foo()? As seen, "a.foo()" works OK! Isn't it
supposed to be illegal?

Any help would be appreciated.

Gary
 
A

Alf P. Steinbach

* ziman137:
Hi all,

The results from following codes got me a bit confused.

#include <stdio.h>
Unnecessary.


#include <iostream>

using namespace std;

struct A {

A () { cout << "A() ctor!" << endl; };

~A() { cout << "~A() dtor!" << endl; };

void foo () { printf("this=%p\n", this); };

Just use standard std::cout.

int x, y;

Not used. Please post not just complete, but minimal, examples. See
the FAQ item "How do I post a question about code that doesn't work
correctly?" currently at <url:
http://www.parashift.com/c++-faq-lite/how-to-post.html#faq-5.8>

};


main ()

Should not compile; see the FAQ item "Should I use void main() or int
main()?" currently at <url:
http://www.parashift.com/c++-faq-lite/newbie.html#faq-29.3>

{

A& a = a;

Should not compile; §8.5.3/1 "A variable declared to be a T&, that is
"reference to type T" (8.3.2), shall be initialized by an object", also
§8.3.2/4 "A reference shall be initialized to refer to a valid object or
function", and 'a' is not a valid object.
 
Z

ziman137

Alf said:
* ziman137:

Just use standard std::cout.



Not used. Please post not just complete, but minimal, examples. See
the FAQ item "How do I post a question about code that doesn't work
correctly?" currently at <url:
http://www.parashift.com/c++-faq-lite/how-to-post.html#faq-5.8>



Should not compile; see the FAQ item "Should I use void main() or int
main()?" currently at <url:
http://www.parashift.com/c++-faq-lite/newbie.html#faq-29.3>

Thanks. I have corrected all above and re-posted my code and results
below.
Should not compile; §8.5.3/1 "A variable declared to be a T&, that is
"reference to type T" (8.3.2), shall be initialized by an object", also
§8.3.2/4 "A reference shall be initialized to refer to a valid object or
function", and 'a' is not a valid object.

Thanks for your answer. I did understand this.

It should not compile? If a reference object is assumed to be just
initialized in the manner of an internal pointer, which points to the
target "object" address, or is assigned by target "this" pointer, it
may well compile. No doubt it is a bad statement - my question is, how
exactly does C++ standard prevent this "should-not" from happening?

By the way, this was exactly where I got confused. My problem was, it
did compile using GNU C++ on Linux (Redhat, see below). Not only being
compiled, it also invokes "a.foo()" OK. Could you, or someone else,
please help me understand whether this is a compiler implementation
issue, or this has something to do with the reference initialization in
ISO C++ standard?

Thankfully,
Gary

------------

PS. Corrected Code to Conform to Group Posting Standard

// foo.cpp
#include <iostream>
using namespace std;

struct A {

A () { cout << "A() ctor!" << endl; };
~A() { cout << "~A() dtor!" << endl; };

void foo () { cout << "this=" << this << endl; };

};


int main ()
{

A& a = a; // it does compile with GNU C++ compiler
cout << "&a=" << &a << endl;
a.foo(); // is it legal here?

A a1;
A& a2 = a1;
cout << "&a1=" << &a1 << endl;
cout << "a2."; a2.foo();

return 0;

}

gcc version 3.2.2 20030222 (Red Hat Linux 3.2.2-5)
g++ -o foo foo.cpp
foo
&a=0x80488ba
this=0x80488ba
A() ctor!
&a1=0xbfffd8e0
a2.this=0xbfffd8e0
~A() dtor!
 
A

Alf P. Steinbach

* ziman137:
Thanks for your answer. I did understand this.

It should not compile? If a reference object is assumed to be just
initialized in the manner of an internal pointer, which points to the
target "object" address, or is assigned by target "this" pointer, it
may well compile. No doubt it is a bad statement - my question is, how
exactly does C++ standard prevent this "should-not" from happening?

Sorry, bad wording or perhaps thinking: it shouldn't compile /cleanly/.

The C++ standard can't prevent it from happening, because a reference
that's not to a valid object can be produced by code that's impossible
to analyse -- e.g., whether the reference is valid or not could depend
on the solution to some intractable mathematical problem.

The wording "shall" above means that if the code does produce a
rerefence that's not to a valid object, it has Undefined Behavior.

A quality compiler will detect the most flagrant violations, such as the
above, and issue a diagnostic (warning or error), just as with e.g.
calling a pure virtual function from a constructor -- which is the
same kind of impossible-to-analyze problem for the general case. Comeau
Online 4.3.3 with default settings warns about your code. Visual C++
7.1 with /W4 warns. MingW g++ 3.4.4 with -Wall and -pedantic warns.

With some compilers you have to instruct them to issue warnings. Since
I have that by default I don't know whether the compilers mentioned will
issue warnings if you don't up the default warning level. But that's
tool usage.

By the way, this was exactly where I got confused. My problem was, it
did compile using GNU C++ on Linux (Redhat, see below). Not only being
compiled, it also invokes "a.foo()" OK.

Not OK: undefined behavior means undefined behavior, including what one
might "expect" were it not for the undefined behavior.
 
J

John Carson

ziman137 said:
Thanks for your answer. I did understand this.

It should not compile? If a reference object is assumed to be just
initialized in the manner of an internal pointer, which points to the
target "object" address, or is assigned by target "this" pointer, it
may well compile. No doubt it is a bad statement - my question is, how
exactly does C++ standard prevent this "should-not" from happening?

By the way, this was exactly where I got confused. My problem was, it
did compile using GNU C++ on Linux (Redhat, see below). Not only being
compiled, it also invokes "a.foo()" OK. Could you, or someone else,
please help me understand whether this is a compiler implementation
issue, or this has something to do with the reference initialization
in ISO C++ standard?

It doesn't have anything specifically to do with references.

A a = a;

will also compile on VC++ 8 and Comeau online. It is a nonsense, just like
your code. It involves undefined behaviour, but lots of things that involve
undefined behaviour still compile. Some of them also run correctly. That is
what undefined means --- the outcome could be anything. Empirical
observation suggests that nonsense initializations will "work" if your class
does not in fact have anything that needs initializing (or if you make no
use of the stuff that does).

Likewise your

a.foo();

is undefined behaviour that you can sometimes get away with.

Try this:

A * ptr;

ptr->foo();

That probably works too.

PS. Corrected Code to Conform to Group Posting Standard

// foo.cpp
#include <iostream>
using namespace std;

struct A {

A () { cout << "A() ctor!" << endl; };
~A() { cout << "~A() dtor!" << endl; };

void foo () { cout << "this=" << this << endl; };

};


int main ()
{

A& a = a; // it does compile with GNU C++ compiler
cout << "&a=" << &a << endl;
a.foo(); // is it legal here?

A a1;
A& a2 = a1;
cout << "&a1=" << &a1 << endl;
cout << "a2."; a2.foo();

return 0;

}

gcc version 3.2.2 20030222 (Red Hat Linux 3.2.2-5)
&a=0x80488ba
this=0x80488ba
A() ctor!
&a1=0xbfffd8e0
a2.this=0xbfffd8e0
~A() dtor!

Running this is debug mode under VC++ 8 gives:

&a=CCCCCCCC
this=CCCCCCCC
A() ctor!
&a1=0012FF37
a2.this=0012FF37
~A() dtor!

The CCCCCCCC address values indicate uninitialized data (in debug mode only,
the compiler initializes the variables to CCCCCCCC, so that if they stay
that way, then you know the program has failed to initialize them).
 
J

John Carson

ziman137 said:
Thanks for your answer. I did understand this.

It should not compile? If a reference object is assumed to be just
initialized in the manner of an internal pointer, which points to the
target "object" address, or is assigned by target "this" pointer, it
may well compile. No doubt it is a bad statement - my question is, how
exactly does C++ standard prevent this "should-not" from happening?

By the way, this was exactly where I got confused. My problem was, it
did compile using GNU C++ on Linux (Redhat, see below). Not only being
compiled, it also invokes "a.foo()" OK. Could you, or someone else,
please help me understand whether this is a compiler implementation
issue, or this has something to do with the reference initialization
in ISO C++ standard?

It doesn't have anything specifically to do with references.

A a = a;

will also compile on VC++ 8 and Comeau online. It is a nonsense, just like
your code. It involves undefined behaviour, but lots of things that involve
undefined behaviour still compile. Some of them also run correctly. That is
what undefined means --- the outcome could be anything. Empirical
observation suggests that nonsense initializations will "work" if your class
does not in fact have anything that needs initializing (or if you make no
use of the stuff that does).

Likewise your

a.foo();

is undefined behaviour that you can sometimes get away with.

Try this:

A * ptr;

ptr->foo();

That probably works too.

PS. Corrected Code to Conform to Group Posting Standard

// foo.cpp
#include <iostream>
using namespace std;

struct A {

A () { cout << "A() ctor!" << endl; };
~A() { cout << "~A() dtor!" << endl; };

void foo () { cout << "this=" << this << endl; };

};


int main ()
{

A& a = a; // it does compile with GNU C++ compiler
cout << "&a=" << &a << endl;
a.foo(); // is it legal here?

A a1;
A& a2 = a1;
cout << "&a1=" << &a1 << endl;
cout << "a2."; a2.foo();

return 0;

}

gcc version 3.2.2 20030222 (Red Hat Linux 3.2.2-5)
&a=0x80488ba
this=0x80488ba
A() ctor!
&a1=0xbfffd8e0
a2.this=0xbfffd8e0
~A() dtor!

Running this is debug mode under VC++ 8 gives:

&a=CCCCCCCC
this=CCCCCCCC
A() ctor!
&a1=0012FF37
a2.this=0012FF37
~A() dtor!

The CCCCCCCC address values indicate uninitialized data (in debug mode only,
the compiler initializes the variables to CCCCCCCC, so that if they stay
that way, then you know the program has failed to initialize them).
 
S

Salt_Peter

ziman137 said:
Hi all,

The results from following codes got me a bit confused.

#include <stdio.h>
#include <iostream>

using namespace std;

struct A {

A () { cout << "A() ctor!" << endl; };

~A() { cout << "~A() dtor!" << endl; };

void foo () { printf("this=%p\n", this); };
a reference itself returns a size of 1
int x, y;

};

always, always initialize your members:

#include <iostream>

struct A
{
A() : m_x(0), m_y(0) { std::cout << "default ctor\n"; }
A(int x, int y) : m_x(x), m_y(y) { std::cout << "param ctor\n"; }
~A() { std::cout << "~dtor\n"; }
private:
int x;
int y;
};

int main()
{

A& a = a;
cout << "&a=" << &a << endl;
a.foo(); // is it legal here?
// a.x = 10; // illegal here
// a.y = 20;

illegal, undefined, a reference must be initialized with a valid object.
C++ is not about side effects particular to your platform/compiler.
A a1;
A& a2 = a1;
cout << "&a1=" << &a1 << endl;
cout << "a2."; a2.foo();

}

gcc version 3.2.2 20030222 (Red Hat Linux 3.2.2-5)
&a=0x80488ce
this=0x80488ce
A() ctor!
&a1=0xbffff0d0
a2.this=0xbffff0d0
~A() dtor!

What does the initialization of a reference object do? Suppose the
initialization of reference is simply has its "this" pointer to the
target object. This does not call constructor, which is true. For
self-referenced "A& a = a", how can its "this" pointer be correctly
bound to member function foo()? As seen, "a.foo()" works OK! Isn't it
supposed to be illegal?

You don't create objects by initialising a reference to a temporary.

a reference is an alias. Just the same as your nickname. Whether i ask
ziman, ganxu or gary to run(): it doesn't matter - the same person is
being asked to run(). For all intensive purposes there is no difference
between a reference and its target. Both share the same this.
Any help would be appreciated.

Gary

What you do need to remember is:
a) a reference cannot be un-initialized.
b) a reference is permanently bound (it can't refer to any other object).
c) a reference can extend the lifetime of an object.
d) references rids a C++ programer of pointer bugs.
 
Z

ziman137

Hi all,

I appreciate all your responses.

By discussing so far, I'd like to clarify my question a bit. My
original intent was to understand what happens "under the hood", when
initializing a reference object by an existing object. say,

class A {
A() {};
// ...
};
int main()
{
A a1;
A& a2 = a1; // What happens here under the hood?
//...
return 0;
}

I wrote the piece of bad code as shown before to explore/manifest what
might be going on when we initialize a reference object. It is
understood that this way to explore/manifest what's going under the
hood runs into the danger of confusion. That is why I was posting my
question here. In the following code,

class A {
A() {};
void foo() {};
// ...
};

int main()
{
A& a = a; // bad
a.foo(); // illegal
return 0;
}

Here we say that, because "A& a = a;" is a bad initialization, so
"a.foo();" is an undefined behavior. It is a very general explanation.
Please be reminded that my intention here is not to understand what
happens in above bad code, but to understand what happens in any legal
and good reference initialization. Yes, a good analogy to reference is
just like the "alias" to a single existing object. However, when you
store any reference (one alias), what do you actually store in C++?
Just simply an internal pointer to the singleton object, or anything
more than that? That was my real intention and question. Please keep
helping me, and any input is welcome.

Thanks again,
Gary
 
O

Owen Jacobson

Hi all,

I appreciate all your responses.

By discussing so far, I'd like to clarify my question a bit. My
original intent was to understand what happens "under the hood", when
initializing a reference object by an existing object. say,

class A {
A() {};
// ...
};
int main()
{
A a1;
A& a2 = a1; // What happens here under the hood?
//...
return 0;
}

The mechanics are not specified by the C++ language, only the semantics.
Compiler vendors are free to implement references however they like, so
long as the results comply with the specified semantics.

Your best bet is to write a short program -- like that one there -- and
examine the compiler's output. That will tell you what happens under that
specific compiler on that platform.

For instance, g++, the GNU C++ compiler, can be coerced into generating an
assembler listing corresponding to a program containing line numbering
information for comparison with the original source with
g++ -S -g foo.c -o foo.S

Other compilers may have similar options. Alternately, there are tools
for examining the resulting object file from normal compilation.

-Owen
 
T

Tomás

ziman137 posted:
int main()
{
A a1;
A& a2 = a1; // What happens here under the hood?


In this particular instance, I would imagine what goes on under the hood is
very similar to:

#define a2 a1


If you're passing by reference, or returning by reference, then I would
imagine that the "hidden pointers" concept comes into play.

A fruitful exercise for trying to understand out how C++ works under the
hood, is to write a C program which emulates those features.

Here's an example of C code I wrote to emulate virtual functions:

http://groups.google.ie/group/comp.lang.c++/msg/5ef38aa42328d25d?hl=en&


-Tomás
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,071
Latest member
MetabolicSolutionsKeto

Latest Threads

Top