athos athos - 1 month ago 10x
C++ Question

Why using a string literal causes dangling pointer?

I'm watching Large-Scale Refactoring at Google talk by Hyrum Wright at CppCon 2014 , at 05'43" he quoted an example that instead of writing

void foo(bool x) {
map<int, string> m = …;
const string& foo = FindWithDefault(m, "key", "default");

one shall write

void foo(bool x) {
map<int, string> m = …;
string default = “default”;
const string& foo = FindWithDefault(m, "key", default); // default, not "default"

because the former will cause dangling pointer error.

I just couldn't see the difference? why there'll be a dangling pointer?

Explanation: The code is copied from the official slides AS-IS.


The actual details here are scant, but it's possible to figure this out based on the context.

The third parameter to FindWithDefault() must be a const std::string &, and this function also returns a const std::string &.

Because the actual parameter


must be converted to a std::string, a temporary object gets constructed for that purpose.

That temporary object gets destroyed after FindWithDefault() returns. Based on the context, it looks like FindWithDefault() will return its third parameter, in this case.

So, it will end up returning a reference to a temporary object, that gets immediately destroyed.

In the second case, the reference remains valid as long as the default object remains in scope, because that's what the reference that's returned from FindWithDefault() is referencing. In the first case, it will be referencing a destroyed temporary object.

A final postscriptum: after some period of working with C++, one will learn to avoid common pitfalls that result in unexpected surprises. A function returning a reference to something is just asking for trouble. There's nothing technically wrong with that, but unless you keep a tight leash on your object, the unexpected could easily happen, resulting in burning massive amounts of time, tracking down an obscure bug of this nature. FindWithDefault() should return a std::string instead of a const std::string &, and this would be a non-issue.