6

I'm new to c++ and would like to know if there is a way to create an object in a function and then return that object without it having to be copied in memory. I know the original local object goes out of scope, but I hoped the compiler could optimize it in a way that the copy of the object would just reuse the same memory adress.

int foo()
{
    int bar = 5;
    std::cout << &bar << std::endl;

    return bar;
}

int main()
{
    char a;
    auto b = foo();
    std::cout << &b << std::endl;
    std::cin >> a;
    return 0;
}

This returns different memory addresses. Since the address of bar is no longer needed and b is always the same size, is there any reason it couldn't just use the same address and save the step of copying?


It doesn't really matter for a simple integer but for larger Objects, what would be the preferred way to make sure the returned object does not get copied in memory?

Would the following be a good approach?

int & foo(int & bar)
{
    std::cout << &bar << std::endl;
    // do things with bar
    return bar;
}

int main()
{
    char a;
    auto bar = 5;
    auto & b = foo(bar);
    std::cout << &b << std::endl;
    std::cin >> a;
    return 0;
}

As a side question, why does the following thing work:

int & foo()
{
    int bar = 5;
    std::cout << &bar << std::endl;

    return bar;
}

int main()
{
    char a;
    auto & b = foo();
    std::cout << &b << " " << b << std::endl;
    std::cin >> a;
    return 0;
}

I expected that bar is out of scope and could no longer be referred to, but this compiles and returns the correct value (MSVC++ 2013).

BoshWash
  • 5,320
  • 4
  • 30
  • 50
  • The question indicated as a duplicate deals with large objects. I think the OP here is more interested specifically in the `int` case. – Christian Hackl Mar 14 '15 at 12:36
  • @ChristianHackl The emphasis seems to be the cost of copying, but it really makes no difference if you have `int` or `BigObject`, which should be clear from answers to the duplicate or this question. But I am happy to re-open this if deemed useful. – juanchopanza Mar 14 '15 at 12:39
  • @juanchopanza: Well, actually, I would not be able to tell the OP why e.g. VC does not optimise away the `int` copy with full optimiation flags. If you replace `int` with `std::string`, the same address will be printed. I suspect that such an optimisation would somehow be pointless, so I hoped to see some enlightening responses specifically on that aspect. (OTOH, I may be interpreting too much into the OP's question here.) – Christian Hackl Mar 14 '15 at 12:49

2 Answers2

4

It doesn't really matter for a simple integer but for larger Objects, what would be the preferred way to make sure the returned object does not get copied in memory?

Just return the object. C++ has return value optimization which means the copy can be (and most often is) elided:

big_object get_object()
{
    big_object bo;
    ....
    return bo;
}

....

big_object big = get_object(); // big gets built in-place

If you look at the address of bo inside the function and big outside, you would expect to see the same address (although RVO is an optimization that can happen, but doesn't have to, so there are other factors that could influence whether you see the same address. With recent g++ and clang++ I get the same address for objects of size 8 bytes, but not for size 4.) For example, this produces the same address on clang++ 3.5:

#include <iostream>

struct foo { int i[2]; };

foo make_foo()
{
  foo f;
  std::cout << &f << std::endl;
  return f;
}

int main()
{
  foo f = make_foo();
  std::cout << &f << std::endl;
}
juanchopanza
  • 223,364
  • 34
  • 402
  • 480
1

If your compiler follows the C++ standard, there's no need to use strange code: the compiler is in fact allowed (according to the standard) to optimize the returning of values from functions, omitting any copy (just Google "c++ return value optimization"). This way, you can even return big structures on the stack by value, without worrying.

EDIT: Answer corrected, thanks to juanchopanza.

lodo
  • 2,314
  • 19
  • 31
  • 2
    The "compiler" could optimize away copies when returning by value way before C++11. Return value optimization has existed for a long time. – juanchopanza Mar 14 '15 at 12:12
  • 1
    So technically this is correct, but misleading (suggests RVO doesn't work before C++11.) – juanchopanza Mar 14 '15 at 12:22
  • @juanchopanza You're right, I confused rvo with r-value references. I'll change the answer accordingly. – lodo Mar 14 '15 at 13:05