const reference to object returned by value

R

rwf_20

Hi,

I'm looking at the differences between:

const NonTrivialObject& obj =
functionThatReturnsANonTrivialObjectByValue();

and:

const NonTrivialObject obj =
functionThatReturnsANonTrivialObjectByValue();

My question is, can I expect these two lines to be any different?

I assumed that the object returned by the function becomes a
temporary. In the first line, I thought that the const reference
would be bound to that temporary, causing the temporary to hang around
until the reference dies.

In the second line, I assumed that the temporary returned from the
function is then copied into 'obj'. Hence, the first line saves a
copy. My testing has proven this completely wrong. See the following
code and results. Is there anything in the standard that could
clarify this, or is this completely compiler-specific?

The code below compiled in gcc 3.4.4 outputs:
Start.
Copy!
A
B
C
Copy!
D
E
F

Microsoft CL 14.00.5 (from VS 8.0) outputs:
Start.
Copy!
A
B
Copy!
C
Copy!
D
E
Copy!
F

Code:

#include <iostream>
class testClass {
public:
testClass() { }

testClass(const testClass& t) { std::cerr << "Copy!\n"; }
};

class ObjectFactory {
public:
ObjectFactory() { }
testClass getResidentObject() const {
return m_object;
}

testClass getLocalTempObject() {
return testClass();
}

testClass getLocalObject() {
testClass t;
return t;
}

private:
testClass m_object;
};

int main() {
ObjectFactory of;
std::cerr << "Start.\n";

const testClass& t1 = of.getResidentObject();
std::cerr << "A\n";

const testClass& t2 = of.getLocalTempObject();
std::cerr << "B\n";

const testClass& t3 = of.getLocalObject();
std::cerr << "C\n";

const testClass t4 = of.getResidentObject();
std::cerr << "D\n";

const testClass t5 = of.getLocalTempObject();
std::cerr << "E\n";

const testClass t6 = of.getLocalObject();
std::cerr << "F\n";

return 0;
}

Any insight would be appreciated. Basically, I'm trying to decide if
it's ever worth using a const reference to refer to something returned
from a function.

Ryan
 
S

spekyuman

Hi,

I'm looking at the differences between:

const NonTrivialObject& obj =
functionThatReturnsANonTrivialObjectByValue();

and:

const NonTrivialObject obj =
functionThatReturnsANonTrivialObjectByValue();

My question is, can I expect these two lines to be any different?

I assumed that the object returned by the function becomes a
temporary. In the first line, I thought that the const reference
would be bound to that temporary, causing the temporary to hang around
until the reference dies.

In the second line, I assumed that the temporary returned from the
function is then copied into 'obj'. Hence, the first line saves a
copy. My testing has proven this completely wrong. See the following
code and results. Is there anything in the standard that could
clarify this, or is this completely compiler-specific?

The code below compiled in gcc 3.4.4 outputs:
Start.
Copy!
A
B
C
Copy!
D
E
F

Microsoft CL 14.00.5 (from VS 8.0) outputs:
Start.
Copy!
A
B
Copy!
C
Copy!
D
E
Copy!
F

Code:

#include <iostream>
class testClass {
public:
testClass() { }

testClass(const testClass& t) { std::cerr << "Copy!\n"; }

};

class ObjectFactory {
public:
ObjectFactory() { }
testClass getResidentObject() const {
return m_object;
}

testClass getLocalTempObject() {
return testClass();
}

testClass getLocalObject() {
testClass t;
return t;
}

private:
testClass m_object;

};

int main() {
ObjectFactory of;
std::cerr << "Start.\n";

const testClass& t1 = of.getResidentObject();
std::cerr << "A\n";

const testClass& t2 = of.getLocalTempObject();
std::cerr << "B\n";

const testClass& t3 = of.getLocalObject();
std::cerr << "C\n";

const testClass t4 = of.getResidentObject();
std::cerr << "D\n";

const testClass t5 = of.getLocalTempObject();
std::cerr << "E\n";

const testClass t6 = of.getLocalObject();
std::cerr << "F\n";

return 0;

}

Any insight would be appreciated. Basically, I'm trying to decide if
it's ever worth using a const reference to refer to something returned
from a function.

Ryan

Look at your type definitions. "const Type& myObj" is a constant
reference and "const Type myObj" is a constant object. In either case
you are not allowed to change the value after initialization. Any
attempt to change their contents should throw a compiler warning/
error. And yes, you can expect these lines to be very different from
one another. Read some articles on C++ references and constant
modifiers.
 
R

rwf_20

Look at your type definitions. "const Type& myObj" is a constant
reference and "const Type myObj" is a constant object. In either case
you are not allowed to change the value after initialization. Any
attempt to change their contents should throw a compiler warning/
error.

I'm aware of that. I don't think my question really has anything to
do with const.
And yes, you can expect these lines to be very different from
one another.

Really? Because the output of my tests implies that they are the same
with respect to creation of temporaries and calls to the copy
constructor. I understand that the result of each statement is
different (a reference vs. an object). But, other than that, each
results in a variable that can be used the same way and have the same
lifetime. How did you mean they would be 'very different'?
 
J

Joe Greer

There are a couple of effects that are coming into play with your code.

1) RVO and NRVO can often remove copies. (You will get much the same
output as gcc with MSVC if you turn on full optimizations as MSVC doesn't
apply NRVO optimisations normally).

2) However, that isn't what's causing the confusion. What is causing the
confusion is that code like:

const testClass t4 = of.getResidentObject();

isn't actually doing an assignment. It is instead invoking the constructor
for t4 with of.getResidentObject() as it's argument. That immediately
removes one of your expected copies.

Try using non-const declarations and then declaring it like:

testClass t4;
t4 = of.getResidentObject();

I would expect to see a difference then.

joe
 

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,997
Messages
2,570,239
Members
46,827
Latest member
DMUK_Beginner

Latest Threads

Top