Crash for lvalue reference binding to return-by-va

2019-07-16 01:56发布

MSVC is accepting this snippet

#include <iostream>
#include <string>
#include <vector>

std::string retstr() {
 return std::string("HelloWorld");   
}

void callFunc(std::string& ref) {
 std::cout << ref;   
}

int main()
{
    callFunc(retstr());
}

for some backward compatibility reason.

Now.. I'm getting some crashes in a DLL in a function which works exactly like this snippet above: the compiler didn't warn me of having a lvalue reference binding to a ret-by-value thingy.

My question is: this is probably not standard but could it cause a program crash (access violation to be precise)?

2条回答
放我归山
2楼-- · 2019-07-16 02:34

The code as written is fine regarding lifetimes, since the temporary value retstr() lives until the end of the full-expression, so it lives as long as the function call.

The fact that MSVC allows binding a lvalue reference to an rvalue does not change that. As always, you have to make sure that callFunc does not store references into the string beyond the duration of the function call.

查看更多
虎瘦雄心在
3楼-- · 2019-07-16 02:37

Binding non constant reference to "rvalue" should definitely be flagged by the compiler .However if compiler is not flagging it ( as in your case ) , it would be problematic at run time(may crash also) .

void callFunc(std::string& ref) {
 std::cout << ref;   //what to display?? if temporary is referenced. 
}

int main()
{
    callFunc(retstr()); //would return temporary which will be lost       immidiately.
}

In your example temporary is being reference which unfortunately was not flagged by the compiler .Now , when this reference (ref) is utilized , it may crash as it is pointing to something which lost .

I would like to share few points which may be useful .

  • If you implement only
    • void foo(X&); without void foo(X&&), the behavior is as in C++98: foo() can be called for lvalues but not for rvalues.
  • If you implement only
    • void foo(const X&); without void foo(X&&), the behavior is as in C++98: foo() can be called for lvalues as well as for rvalues.
  • If you implement
    • void foo(X&);
    • void foo(X&&);
    • or void foo(const X&);
    • void foo(X&&); you can distinguish between dealing with rvalues and lvalues. The version for rvalues is allowed to and should provide move semantics. Thus, it can steal the internal state and resources of the passed argument. last one is supported in c++11 only .
查看更多
登录 后发表回答