0

I'm quite confused about returning an object from a function. For example:

class A
{
public:
    ~A(){}
};

A find()
{
    ...
    A a;
    return a; 
}

Does it return "a" by reference or by value? Moreover, does "find" delete "a" first, then return or return first, then delete "a"?

Tki Lio
  • 263
  • 1
  • 8
  • 3
    You have to explicitly request references in C++. You didn't, so it's return by value. – user4581301 Aug 29 '18 at 16:28
  • 5
    Officially what's returned is a copy and the original is destroyed, but modern compilers go out of their way to avoid the copy and destruction. Search term: Copy Elision. – user4581301 Aug 29 '18 at 16:30
  • Near Duplicate and good reading: [Returning an object in C++](https://stackoverflow.com/questions/11379797/returning-an-object-in-c) – user4581301 Aug 29 '18 at 16:37
  • Had to go a bit out of the box, but the many answers here cover the rest of the question: [What are copy elision and return value optimization?](https://stackoverflow.com/questions/12953127/what-are-copy-elision-and-return-value-optimization) – user4581301 Aug 29 '18 at 16:55
  • Possible duplicate of [Returning an object in C++](https://stackoverflow.com/questions/11379797/returning-an-object-in-c) – Mikel F Aug 29 '18 at 18:53

2 Answers2

3

In your function, you are returning a value, not reference.

A find();

return type is A. Is is value, a copy of a will return.

In order to return a reference, you should write your function as follows.

A& find();

return type A& means a reference to A. But your function body should be change accordingly, in order to return a valid reference.

With the current implementation, you are creating object a inside the function. So it get delete when it goes out of the scope, at the end of function execution.

Your question "Moreover, does "find" delete "a" first, then return or return first, then delete "a"?"

copy of a will return first, then a will delete.

If you return a reference, reference will be return, then object a will get deleted.

In this code you return by value and this is where return value optimization comes(RVO) in to the play. a copy of 'a' is created, then origianal 'a' deleted, return copy of 'a'. The correct sequence is not sure.

ANjaNA
  • 1,404
  • 2
  • 16
  • 29
  • "copy of a will return first, then a will delete." I've been mulling this over and I cannot find anything in the C++ Standard guaranteeing this ordering. I suspect it will be more like make copy, destroy `a`, return copy. if RVO doesn't eliminate all of the copying and destruction. – user4581301 Aug 29 '18 at 17:07
  • deleting happen when it is going out of scope only. that mens at the end of returning right ? – ANjaNA Aug 29 '18 at 17:09
  • 1
    What I'm trying to get at is it really doesn't matter which happens first when the goal should be not doing any of them. – user4581301 Aug 29 '18 at 17:19
  • 1
    @user4581301 return semantics wouldn't make sense if it was the other way around. First destroy `a` and then copy it to return it? That makes no sense. Anyway, neither will happen with RVO. – Hatted Rooster Aug 29 '18 at 17:19
  • 1
    @SombreroChicken agree on that. The copy, if it takes place, must be before destruction, but destruction after the function has returned doesn't make much sense either. I think where I'm going wrong is looking for answers in the C++ Standard when I should be looking at the calling convention. – user4581301 Aug 29 '18 at 17:24
  • 1
    @user4581301 Exactly. I think it states nowhere that `a` should be returned or a copy of `a` before returning and after destroying a` in the standard so that won't get you anywhere. – Hatted Rooster Aug 29 '18 at 17:24
  • @ANjaNA you mean another "a" is created, and the original "a" in find() will be deleted, don't you? – Tki Lio Aug 29 '18 at 17:26
  • 1
    @TkiLio another `A` may be constructed from `a` using `A`'s copy constructor. `a` will be deleted if `a` is copied. Otherwise any of dozens of tricks will be used to avoid copying and destroying at all. For example, the caller may be required pass in sufficient storage to allow `find` to construct `a` in the caller's space on the stack. No copying or destruction is required because `a` no longer needs to be destroyed on return. – user4581301 Aug 29 '18 at 17:33
  • 1
    I'm confused now because it is nonsense if "a" is returned, then being deleted, how can we get "a" in the caller? – Tki Lio Aug 29 '18 at 17:35
  • 1
    When passing by value `a` is never actually returned. Either a copy of it is returned or the program is arranged by the compiler such that `a` never needs to be returned. Any time the compiler can shuffle things around to eliminate work without getting caught, it will. See [The As If Rule](https://stackoverflow.com/questions/15718262/what-exactly-is-the-as-if-rule). However, return by value is one of the cases where the compiler is allowed to eliminate work AND get caught. RVO is allowed to eliminate side effects in the name of faster code. – user4581301 Aug 29 '18 at 17:41
  • 1
    @TkiLio though it doesn't look like it, you've actually asked a pretty hard question. Most of it is covered in [What are copy elision and return value optimization?](https://stackoverflow.com/questions/12953127/what-are-copy-elision-and-return-value-optimization) – user4581301 Aug 29 '18 at 17:42
  • 1
    Example code to demonstrate: https://ideone.com/eFBZRj note how no copying or assignment is performed and there is only one destruction right at the end of the program – user4581301 Aug 29 '18 at 17:57
  • thanks for all the suggestions. I understand RVO comes in to the action. I've update the answer accordingly. Thanks again all. – ANjaNA Sep 02 '19 at 12:29
2

The easy part: Does it return "a" by reference or by value?

A find()
{
    ...
    A a;
    return a; 
}

Returns by value.

The hard part: Moreover, does "find" delete "a" first, then return or return first, then delete "a"?

Technically a copy of a is constructed, a is destroyed and the copy is returned. I cannot find anything in the C++ standard that specifies any particular ordering to those operations, but some are logically implied. Obviously you cannot copy after destruction.

I suspect this is left unspecified to allow C++ implementations to support a wide variety of calling conventions.

Note: This means the returned object must be copy-able. If the copy constructor is deleted or inaccessible, you cannot return by value.

There is no way to be certain of whether the return or the destruction is first. It should not matter and if you are designing a program where it does, give your head a shake.

Caveat

However in practice a modern optimizing compiler will do anything in its power to avoid copying and destroying using a variety of approaches under the blanket name of Return Value Optimization.

Note that this is a rare case where the As-If Rule is allowed to be violated. By skipping the copy construction and destruction, some side effects may not take place.

Also note that even if the need to copy is eliminated, the object must still be copy-able.

Sidenote:

A & find()
{
    ...
    A a;
    return a; 
}

will return a reference, but this is a very bad idea. a has Automatic storage duration scoped by the function and will be destroyed on return. This leaves the caller with a dangling reference, a reference to a variable that no longer exists.

To get around this,

std::unique_ptr<A> find()
{
    ...
    auto a = std::make_unique<A>();
    return a; 
}

but you will find that, with a modern compiler, this is no better than returning by value in most cases.

Community
  • 1
  • 1
user4581301
  • 33,082
  • 7
  • 33
  • 54