Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reference to element of vector returned by a function in C++

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?

like image 428
user2170028 Avatar asked Mar 14 '13 13:03

user2170028


People also ask

Can a function return a vector in C?

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.

Which function returns a reference to the first element in a vector?

vector::front() This function can be used to fetch the first element of a vector container.

Which function returns a reference to the last element in a vector?

The C++ function std::vector::back() returns a reference to the last element of the vector.

How do you retrieve an element from a vector?

get() method is used to fetch or retrieve an element at a specific index from a Vector.


2 Answers

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.

like image 173
David Rodríguez - dribeas Avatar answered Nov 10 '22 17:11

David Rodríguez - dribeas


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.

like image 38
LihO Avatar answered Nov 10 '22 19:11

LihO