Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

costless boost::make_tuple return by value

50 views
Skip to first unread message

porp...@gmail.com

unread,
Oct 31, 2014, 1:03:53 PM10/31/14
to
Hi,

I found that returning from my_fun is costless. None of the constructors or assignment operator of Human is called.
I expect the non-default constructor of Human to be called as the result of "return value optimization".
Why is that ?

I compiled it as follows (no c++11):
g++ -O0 my_prog.cpp

I use gcc 4.9.1 and boost 1.56.0.

#include <iostream>
#include <boost/tuple/tuple.hpp>

using namespace boost;
using namespace std;

class Human
{
public:
string m_name;

Human(void)
{
cout << "Human default constructor" << endl;
}

Human(string name) : m_name(name)
{
cout << "Human non-default constructor" << endl;
}

Human(const Human &b) : m_name(b.m_name)
{
cout << "Human copy constructor" << endl;
}

Human &operator=(const Human &right)
{
cout << "Human operator=" << endl;
m_name = right.m_name;
return *this;
}
};

boost::tuple<Human, string> my_fun(void)
{
Human h("xx"); // constructor
string pet("zz");
return boost::make_tuple(h, pet); // make_tuple calls copy constructor
}

int main(void)
{
boost::tuple<Human, string> myTuple = my_fun (); // nothing is called (excluding the constructor called inside my_fun and copy constructor called by make_tuple). Does this mean that return operation is costless ? How can it be ?
return 0;
}

thanks for clarification

Victor Bazarov

unread,
Oct 31, 2014, 1:35:45 PM10/31/14
to
On 10/31/2014 1:03 PM, porp...@gmail.com wrote:
> I found that returning from my_fun is costless. None of the constructors or assignment operator of Human is called.
> I expect the non-default constructor of Human to be called as the result of "return value optimization".
> Why is that ?

Why is what? Why is it that you expect the non-default c-tor of Human
to be called? I don't know. Why do you?

RVO allows the compiler to eliminate copying from the value in the
'return' expression in some function whose body the compiler can see,
when that value is used to initialize another object of the same type.

blah func_returning_a_blah()
{
...
return some_blah;
}
...
blah b = func_returning_a_blah(); // no copying due to RVO

If the compiler can see the function, it will inline the code in such a
way so it initialized the 'some_blah' directly into 'b'.
Costless, yes. What's the big deal?

As an experiment, move 'my_fun' function definition to a separate
translation unit, and you *might* see a copy made, depending on how
clever your compiler is. However, often the compiler can create a
hidden "argument" for a value-returning function for the return value
(since it is needed by the caller anyway), and in the case of the
initialization, the address of the object being initialized is going to
be used as that hidden "argument", so even after moving the function so
it can't be inlined any longer, you are still going to see no copy made.

> return 0;
> }
>
> thanks for clarification
>

V
--
I do not respond to top-posted replies, please don't ask

Paavo Helde

unread,
Oct 31, 2014, 2:46:37 PM10/31/14
to
porp...@gmail.com wrote in
news:fecec3a1-2ba6-48e0...@googlegroups.com:

> "return value optimization"
> How can it be ?

I have understood that typically the caller reserves some space on the
stack for the result variable and passes its address to the called
function. When the function comes around to construct the return value or a
named variable which will be returned later, it constructs it directly at
the specified address. This requires some cooperation between the caller
and the called function. For details see

http://en.wikipedia.org/wiki/Return_value_optimization

porp...@gmail.com

unread,
Nov 26, 2014, 10:46:11 AM11/26/14
to
Thanks to both of you for the reply. It looks like I wasn't aware of how powerfull the RVO is. Now I agree with you.
0 new messages