Dangling Reference

K

kaede

Hi all,

I have a quick question regarding binding temporary to const
reference. I wrote a little toy program to test it, but I don't seems
to understand the behaviour. Consider the following code snipplet:

// Data class, also overload operator<<
class Data { ... };

// Holds the data
class DataHolder
{
public:
DataHolder(Data data_): m_data(data_) {} // 1
void dump() const { cout << m_data << "\n"; }

private:
const Data& m_data;
};

Scenerio A)

int main()
{
DataHolder holder( Data(....) );

// this line will dump out some garbage. My understanding is that
// The member variable m_data binds to a temporary copied of Data
// and when the DataHolder constructor completes, the temporary is
// destroyed that, the m_data reference is no longer valid
holder.dump();

return 1;
}

Scenerio B)
int main()
{
Data data( .. );
DataHolder holder( data );

// this line successfully dump the contents of data. I am not sure
why?
// shouldn't it behaves the same Scenerio A?
holder.dump();
return 1;
}

Scenerio C)
Change the DataHolder constructor to the following

DataHolder(Data& data_): m_data(data_) {} or
DataHolder(const Data& data_): m_data(data_) {}

int main()
{
Data data( .. );
DataHolder holder( data );

// this line successfully dump the contents of data. I am not sure
why?
holder.dump();
return 1;
}

Scenerio D)
Now, rather than using Data as a class, we change data to the
following:

enum Data
{
LONG,
FLOAT,
INT
};

When re-running scenerio A - C, the contents of data seems to be
dumping out
correctly. I am not sure why?

Can anyone enlighten me? Your help is appreciated. Thanks!!!!

Kaede
 
R

Ron Natalie

kaede said:
When re-running scenerio A - C, the contents of data seems to be
dumping out
correctly. I am not sure why?
Because one of the insidious features of undefined behavior is that things
might appear to work normally (only to fail later).

In Scenario A, you have it right. The temporary ceases to be as soon
as the constructor finishes.

In Scenario B, you have undefined behavior. What happens if you
change the member of data after holder is constructed but before
you print? I suspect either that you are benefiting from the eliding
of the temporary or somehow the reference ends up seated at the
variable in main. In either case it's just a conincidence.

Scenario C, you don't have undefined behavior. There is no temporary.
The reference in holder refers to the variable data in main. It lives longer
than holder does in fact.

In Scenario D, you just get more coincidental behavior, but you've changed
the data object's size so that it's really small and may end up being parked
in a register.
 
K

kaede

Ron Natalie said:
Because one of the insidious features of undefined behavior is that things
might appear to work normally (only to fail later).

In Scenario A, you have it right. The temporary ceases to be as soon
as the constructor finishes.

In Scenario B, you have undefined behavior. What happens if you
change the member of data after holder is constructed but before
you print? I suspect either that you are benefiting from the eliding
of the temporary or somehow the reference ends up seated at the
variable in main. In either case it's just a conincidence.

Scenario C, you don't have undefined behavior. There is no temporary.
The reference in holder refers to the variable data in main. It lives longer
than holder does in fact.

In Scenario D, you just get more coincidental behavior, but you've changed
the data object's size so that it's really small and may end up being parked
in a register.

Thanks ... I think I see what is happening.

Regards,
Kaede
 
K

kaede

Ron Natalie said:
Because one of the insidious features of undefined behavior is that things
might appear to work normally (only to fail later).

In Scenario A, you have it right. The temporary ceases to be as soon
as the constructor finishes.

In Scenario B, you have undefined behavior. What happens if you
change the member of data after holder is constructed but before
you print? I suspect either that you are benefiting from the eliding
of the temporary or somehow the reference ends up seated at the
variable in main. In either case it's just a conincidence.

Scenario C, you don't have undefined behavior. There is no temporary.
The reference in holder refers to the variable data in main. It lives longer
than holder does in fact.

In Scenario D, you just get more coincidental behavior, but you've changed
the data object's size so that it's really small and may end up being parked
in a register.

I was thinking about it this morning and what would happened if I
modified Scenerio C to the following:

int main()
{
DataHolder* p = 0;

{
Data data( ... );

p = new DataHolder(data);

} // (2)

// would this cause undefined behaviour since data already get
destroyed
// after (2). or will the const& m_data prolongs the scope of
data?
p->getType();
}

Similarily, what if it is in different translational unit:

// a.cxx
void A::registerData(Data& data_)
{
DataHolder* p = new DataHolder(data_);

C::registerDataHolder(p);
}

// b.cxx
void B::someFunc()
{
Data data(..);

A.registerData(data);
}

Also, I read something about when temporary binds to const&, the
const& that binds to the temporary will prolongs the life of the
temporary. That is the
temporary will be destroyed when the const& is destoyed. Is that
correct, I don't think I understand the meaning and the usefulless of
it. Can anyone explain it to me. Thanks =)

Kaede
 
L

lilburne

kaede said:
I was thinking about it this morning and what would happened if I
modified Scenerio C to the following:

In both cases you'll have undefined behaviour.
 

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,744
Messages
2,569,484
Members
44,904
Latest member
HealthyVisionsCBDPrice

Latest Threads

Top