Personally, I would say that's more a combination of "not Machiavelli-safe" or "not derp-safe" and a quirk of rvalue references than "not memory-safe", since it demonstrates that std::begin() is exactly as memory-safe as the parameter you pass to it, and not inherently unsafe solely in and of itself. That's just me, though.
– Justin TimeFeb 12 at 7:40

6 Answers
6

The get_data function returns an object. When used the way shown, that object will be a temporary object, which will be destructed once the full expression ends. The iterator now references a vector object which no longer exists, and can't be dereferenced or used in any useful way.

I think Eric's point about std::begin is that it silently accepts an rvalue container as an argument to begin with. On the face of it, the problem with the code is also exemplified in

auto it = get_data().begin();

But std::begin is a free function template, it can be made to reject rvalues without needing to add the proper reference qualifiers to each container's begin members. By "just" forwarding it misses an opportunity to add a layer of memory safety to code.

Is it possible for us to make a warning of deprecation or usage for that particular template instantiation instead of outright deleting it? Compiler specific extensions allowed.
– Paul StelianFeb 11 at 9:51

@PaulStelian - No, we can't. I intentionally provided an example in another namespace. To add this overload, we'd need to write a proposal, then get it voted int o the standard.
– StoryTellerFeb 11 at 11:25

3

The thing is, as Alexandrescu points it out with humour in its 2018 cppcon talk, the C++ committee likes to be consistent in its past errors. One might think the reason why std::begin accepts r-values is to let begin(c) and c.begin() be perfectly equivalent. (but yes obviously this overload set would be ideal)
– YSCFeb 11 at 12:24

3

@YSC .begin() could also be made to reject rvalues, couldn't it? iterator begin() && = delete;
– The VeeFeb 11 at 18:00

in fact , the complicated function can be simplified to two short functions , such as

int& foo(int x){
return x;
}
int generate_a_int(){
return 42;
}

and then invoke it foo(generate_a_int()), a temporary value is generated , once out of the function body, the temporary value generated by generate_a_int() is destroy , and then dangle reference is happened ...