Home > Mobile >  Returning a reference to std::vector element results in a crash
Returning a reference to std::vector element results in a crash

Time:08-10

The example below does not crash, but prints nothing with MSVC Compiler Version 19.32.31332 and prints "def" with GCC:

#include <string>
#include <vector>
#include <set>
#include <ranges>
#include <iostream>

template <class R, class Value>
concept range_over = std::ranges::range<R> &&
std::same_as<std::ranges::range_value_t<R>, Value>;

const std::string& find1(const std::vector<std::string>& v)
{
    return v[1];
}

template <range_over<std::string> Range>
std::reference_wrapper<std::string> find2(Range range)
{
    return *(range.begin()   1);
}

int main()
{
    std::vector<std::string> v = { "abc", "def", "ghi" };

    //find1 always prints "def"
    //std::cout << find1(v);

    std::cout << find2(v).get() << std::endl;

    return 0;
}

But in my real-life app a similar code crashes with MSVC Compiler Version 19.32.31332.

Is the code correct? Is v valid after func2(v) call?

CodePudding user response:

find2 takes the range by-value. So you are returning a reference into the function parameter object, which is a copy of the vector v in main, which in itself is very likely not the intention of the function. E.g. modifications through the returned reference would not be reflected in v.


It is implementation-defined whether function parameters are destroyed when the function returns or after the full-expression containing the function call. Practically speaking this will be determined by the C ABI used (which also potentially explains different behavior between MSVC and GCC/Clang).

So, depending on how the implementation used defines this, it may or may not have undefined behavior. If the parameter object is destroyed when the function returns, the call to operator<< will read a value through a dangling reference. Otherwise it is a valid program and will print def.


Before C 17 the standard said that function parameter objects are always destroyed when the function returns. This was changed with CWG issue 1880. As the issue notes however, actual implementations/ABIs did have the (at the time) non-conforming behavior of destroying them at the end of the full-expression and the implementation-definedness in the resolution was chosen so that these ABIs wouldn't break. So practically speaking the standard just adjusted to actual practice.

  • Related