Click to See Complete Forum and Search --> : references&


c94wjpn
March 5th, 2002, 04:05 AM
What's happening here?



class A {

};

A go(void) {
A a;
return a;
}

int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{
A& aa = go();
////
//// --
return 0;
}








In case it's not obvious, I am wondering whether aa is valid since it is a reference to an object which is destroyed or something.

\begin{signature}
digital watches and mobile phones.
\end{signature}

NMTop40
March 5th, 2002, 04:54 AM
go() returns an object, not a copy. If you peak at A's destructor you will find it is called twice - that is because two of A's constructors are called, the default constructor and the copy constructor.

It is for this reason that classes like string will often use shared reference counting on the actual string data they return. Otherwise every time a function returned a string it would have to copy the data (inefficient).


The best things come to those who rate

c94wjpn
March 5th, 2002, 06:53 AM
ok, go() returns an object. What is the lifetime of this object? It seems that this depends on whether there are references to it. Try looking at this in a debugger:


class A {
public:
~A(void) {
static int i(0);
++i;
};

};

A go(void) {
A a;
return a;
}

int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{
int j;
#ifdef V1
A& aa = go();
#else
go();
#endif


j = 0;

return 0;
}





I thought that reference counting was Java, not C++. From this it seems that C++ does some implicit reference counting,
and will not destroy an object if there is a reference to it somewhere.

\begin{signature}
digital watches and mobile phones.
\end{signature}

Graham
March 5th, 2002, 08:14 AM
According to the C++ standard:

a reference initialised with a temporary value makes that temporary value live for the lifetime of the reference itself. (That's the information I've seen, although I've only ever seen a const reference used.)

So, for

/* const? */ A& aa = go();



the temporary has the lifetime of aa, but for

go();



the temporary lives until the semicolon. I suppose you could look on this as reference counting, but it's a very limited form.

He who breaks a thing to find out what it is, has left the path of wisdom - Gandalf

jbschumacher
March 5th, 2002, 02:24 PM
It's a compiler optimization. You don't use the return value, so it gets rid of the object.

Assigning the reference to it, means you do use the return value, so it does have the life of the reference.

Contrary to belief... Win32 API programming is easier and cleaner the MFC...

Graham
March 6th, 2002, 03:11 AM
It's a bit more than just an optimisation: I think the standard says that the temporary lasts to the end of the statement that created it. I have a class that returns an object and I rely on it lasting to the end of the statement:

class C
{
struct Proxy_
{
Proxy_() {}
~Proxy_()
{
TRACE("%s", str.str().c_str());
}
std::ostringstream& str;
};
public:
Proxy_ f()
{
return Proxy_();
}
// other stuff
};

int main()
{
C c;

c.f().str << "messages" << data << etc << endl;
}



What this does is to allow me to build up a string using iostream style and then print it to the debug output window. It relies on the temporary Proxy_ object lasting to the end of the statement, at which point the destructor kicks in to actually print the string to the debug window. I suppose you could argue that I'm using the object, so the optimiser won't throw it away, but this behaviour is, I believe, enshrined in the standard.

He who breaks a thing to find out what it is, has left the path of wisdom - Gandalf