Can someone verify that the following is a BUG, and explain why? I think I know, but am unclear about the details. (My actual problem involved a vector of enums, not ints, but I don't think it should matter.) Suppose I have the following code:
std::vector<int> f (void) {
std::vector<int> v;
v.push_back(5);
return v;
}
void g (void) {
const int &myIntRef = f()[0];
std::cout << myIntRef << std::endl;
}
Am I correct that myIntRef is immediately a dangling reference, because the return value of f is saved nowhere on the stack?
Also, is the following a valid fix, or is it still a bug?
const int myIntCopy = f()[0]; // copy, not a reference
In other words, is the return result of f() thrown away before the 0th element can be copied?
Yes, a function can return a vector in C++ and in different ways. This article explains the different ways in which a C++ function can return a vector. In order to code a vector in C++, the vector library has to be included in the program.
vector::front() This function can be used to fetch the first element of a vector container.
The C++ function std::vector::back() returns a reference to the last element of the vector.
get() method is used to fetch or retrieve an element at a specific index from a Vector.
That is a bug. At the end of the complete expression const int &myIntRef = f()[0];
the temporary vector will be destroyed and the memory released. Any later use of myIntRef
is undefined behavior.
Under some circumstances, binding a reference to a temporary can extend the lifetime of the temporary. This is not one of such cases, the compiler does not know whether the reference returned by std::vector<int>::operator[]
is part of the temporary or a reference to an int
with static storage duration or any other thing, and it won't extend the lifetime.
Yes, it is wrong thing to do indeed. When you call:
return v;
temporary copy of object v
is being created and
const int &myIntRef = f()[0];
initializes your reference with the first element of this temporary copy. After this line, the temporary copy no longer exists, meaning that myIntRef
is an invalid reference, using of which produces undefined behavior.
What you should do is:
std::vector<int> myVector = f();
const int &myIntRef = myVector[0];
std::cout << myIntRef << std::endl;
which (thanks to copy elision) uses an assignment operator to initialize myVector
object by using v
without copy of v
being created. In this case the lifetime of your reference is equal to the lifetime of myVector
object, making it perfectly valid code.
And to your second question:
"Also, is the following a valid fix, or is it still a bug?"
const int myIntCopy = f()[0]; // copy, not a reference
Yes, this is another possible solution. f()[0]
will access the first element of the temporary copy and use its value to initialize myIntCopy
variable. It is guaranteed that the copy of v
returned by f()
exists at least until the whole expression is executed, see C++03 Standard 12.2 Temporary objects §3:
Temporary objects are destroyed as the last step in evaluating the full-expression (1.9) that (lexically) contains the point where they were created.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With