helloworld922
helloworld922

Reputation: 10939

does vector still exist?

std::vector<float> someOp(void)
{
    using namespace std;
    vector<float> results;
    // some operations done to results
    return results;
}

int main(void)
{
    using namespace std;
    vector<float> &results = someOp();
}

Does the vector returned by someOp exist in the someOp() stack space or in the main() stack space?

I'm inclined to believe that it doesn't get copied/moved to the main() stack space since the results vector has the same address inside of both methods.

Upvotes: 2

Views: 240

Answers (4)

The code in the question is incorrect and should be rejected, but still the question would apply to a slight modification of it, but before discussing it lets describe the following simpler program:

type f() {
   type x;        // [1]
   return x;      // [2]
}
int main() {
   type m = f();  // [3]
   m.const_function();
}

In the program above there are conceptually 3 objects, there is x inside f, the returned value that is unnamed and finally m inside main. x is created in [1], then copied to the returned object in [2] which finally is used to copy construct m in [3].

Now back to the reference case:

type f() {
   type x;                // [1]
   return x;              // [2]
}
int main() {
   type const & r = f();  // [3]
   r.const_function();
}

Conceptually, the same thing is going on. An object x is created at [1], and copied to the returned value in [2], now in [3] that returned value is not used to initialize r, but rather to initialize an unnamed object injected by the compiler. Finally, in [3] the constant reference is bound to the unnamed object. At this point, the unnamed object is in the context of main.

As of what actually happens in current compilers, the calling convention determines how the interface of the functions is implemented. The calling convention for a function that returns an object that does not fit in registers is implemented (in all compilers I know) by passing an extra hidden pointer to the function. That is, the caller (main in this case) reserves space in the stack and then passes a pointer to that location into the callee. This is the location where caller and callee agree that the returned object will live. This means that the caller can reserve space for m in the original example or for the unnamed object in the second case and pass the pointer in. This removes one of the objects from the equation as m (or the unnamed object) and the returned object are the same. The next step is performed by the compiler when processing the callee, if it can determine that x will be returned in all code paths, it will not create x in its own stack, but directly on the memory referenced by the hidden pointer. When this is done, the net effect is that there will be a single object in the program:

main will acquire memory, and pass a pointer to f, f will create x on that memory location (which is in main's stack space) and return to main, in the case of the const reference the compiler will alias the unnamed object by the name of the reference.

(Note: the reference and the unnamed object are not the same, their types can actually differ, but the reference will be an alias to the unnamed object that provides a name for it)

Upvotes: 0

Stuart Golodetz
Stuart Golodetz

Reputation: 20656

This doesn't compile portably - in Standard C++, you can't bind a temporary (the std::vector<float> returned by someOp in this case) to a non-const reference.

Upvotes: 2

Mysticial
Mysticial

Reputation: 471489

It's a little more complicated than that.

Yes, it is initially in the stack space of someOp. But since you return by value, a copy is made. So it isn't lost (yet).

However, when you store it into vector<float> &results, you store a reference to it. Which becomes invalid after the statement ends. The returned vector is an intermediate that is destroyed after the statement ends.

So the end result is that vector<float> &results becomes a dangling "pointer".

EDIT : (see comments)

Apparently, the code isn't supposed to compile at all. But it does in VS2010. So my answer only applies to the case where it does compile.

Upvotes: 3

slugonamission
slugonamission

Reputation: 9642

Neither, that's not valid C++ (and doesn't get compiled by g++).

It seems you're trying to store a reference to the returned results, but that's impossible as the returned results exists in the stack frame of someOp, and, while it will still be there just after someOp() returns, will get overwritten at some point in the future.

Upvotes: 5

Related Questions