G
Guest
In the following example, section #3 fails under VC98, VC2003, VC2005 Express
Beta (Aug 2004) and g++ 3.3.2. Is this just a pitfall of the C++
specification? Why don't any of the above compilers at least flag this as a
warning as they would when say trying to return a const & to a local?
In Section #2, the const B& Bref is initialized and bound to the temporary
returned from GetSettings(). That is the temporary B exists until Bref goes
out of scope.
What appears to be happening in section #3 is this:
1. A temporary B object is copy constructed and returned from the
GetSettings() call.
2. The GetData() call on that temporary returns a const & and no temporary
is created for its return, thus Cref2 is initialized to a reference a member
of a temporary object.
3. The temporary B object goes out of scope.
4. The Cref2.Test() call is then made on an object that has passed out of
scope and no longer exists.
When the const C& Cref2 is initialized to refer to a subobject of the
temporary B shouldn't that also cause the temporaries scope to be bound to
that of Cref2?
This behavior was discovered when we changed a rather large class
hierarchy's A::GetSettings() from returning by const & to be a return by
value instead and things quit working correctly. What we thought was a
couple line code re-factor turned out to have this nasty consequence. So I
ask, is the compiler correctly implementing the C++ spec here (or are all the
ones we tested broken)? And, can the compiler produce an error or warning to
alert the programmer?
Thanks
-------snip below here-------
#include <cassert>
#include <iostream>
#include <vector>
using namespace std;
struct C
{
C() : mBuffer(100, 0xDC) {cerr << "C()\n";}
C(const C &c) : mBuffer(c.mBuffer) {cerr << "C(const C &)\n";}
virtual ~C() {mBuffer.clear(); cerr << "~C()\n";}
void Test() const {assert(!mBuffer.empty());}
protected:
vector<char> mBuffer;
};
struct B
{
B() {cerr << "B()\n";}
B(const B &b) : mData(b.mData) {cerr << "B(const B &)\n";}
virtual ~B() {cerr << "~B()\n";}
const C &GetData() const {return mData;}
protected:
C mData;
};
struct A
{
A() {cerr << "A()\n";}
A(const A &a) {cerr << "A(const A &)\n";}
virtual ~A() {cerr << "~A()\n";}
virtual B GetSettings() const {return mSettings;}
protected:
B mSettings;
};
int main(void)
{
A anObject;
//1. This works
anObject.GetSettings().GetData().Test();
//2. This works as well
const B &Bref = anObject.GetSettings();
const C &Cref = Bref.GetData();
Cref.Test();
/*
//3. This doesn't work...no compile warnings or errors, but assert pops
const C &Cref2 = anObject.GetSettings().GetData();
Cref2.Test();
*/
cerr << "End Scope of main()\n";
return 0;
}
Beta (Aug 2004) and g++ 3.3.2. Is this just a pitfall of the C++
specification? Why don't any of the above compilers at least flag this as a
warning as they would when say trying to return a const & to a local?
In Section #2, the const B& Bref is initialized and bound to the temporary
returned from GetSettings(). That is the temporary B exists until Bref goes
out of scope.
What appears to be happening in section #3 is this:
1. A temporary B object is copy constructed and returned from the
GetSettings() call.
2. The GetData() call on that temporary returns a const & and no temporary
is created for its return, thus Cref2 is initialized to a reference a member
of a temporary object.
3. The temporary B object goes out of scope.
4. The Cref2.Test() call is then made on an object that has passed out of
scope and no longer exists.
When the const C& Cref2 is initialized to refer to a subobject of the
temporary B shouldn't that also cause the temporaries scope to be bound to
that of Cref2?
This behavior was discovered when we changed a rather large class
hierarchy's A::GetSettings() from returning by const & to be a return by
value instead and things quit working correctly. What we thought was a
couple line code re-factor turned out to have this nasty consequence. So I
ask, is the compiler correctly implementing the C++ spec here (or are all the
ones we tested broken)? And, can the compiler produce an error or warning to
alert the programmer?
Thanks
-------snip below here-------
#include <cassert>
#include <iostream>
#include <vector>
using namespace std;
struct C
{
C() : mBuffer(100, 0xDC) {cerr << "C()\n";}
C(const C &c) : mBuffer(c.mBuffer) {cerr << "C(const C &)\n";}
virtual ~C() {mBuffer.clear(); cerr << "~C()\n";}
void Test() const {assert(!mBuffer.empty());}
protected:
vector<char> mBuffer;
};
struct B
{
B() {cerr << "B()\n";}
B(const B &b) : mData(b.mData) {cerr << "B(const B &)\n";}
virtual ~B() {cerr << "~B()\n";}
const C &GetData() const {return mData;}
protected:
C mData;
};
struct A
{
A() {cerr << "A()\n";}
A(const A &a) {cerr << "A(const A &)\n";}
virtual ~A() {cerr << "~A()\n";}
virtual B GetSettings() const {return mSettings;}
protected:
B mSettings;
};
int main(void)
{
A anObject;
//1. This works
anObject.GetSettings().GetData().Test();
//2. This works as well
const B &Bref = anObject.GetSettings();
const C &Cref = Bref.GetData();
Cref.Test();
/*
//3. This doesn't work...no compile warnings or errors, but assert pops
const C &Cref2 = anObject.GetSettings().GetData();
Cref2.Test();
*/
cerr << "End Scope of main()\n";
return 0;
}