Will initializing a const reference argument fom a default argument result in a dangling reference?

Viewed 912
void foo(const std::string& s = "abc") {
    // ...
}

// ...

int main() {
    // ...
    foo();
    // ...
}

Will s in foo be dangling? I think because std::string will be constructed from default value "abc", and then this will be a const reference do died temporary.

Am I right?

5 Answers

s will not dangle in foo, but the temporary will live for the entirety of foo. There are a couple pieces that need to be understood to understand why this happens:

  1. When you declare a default argument on the function, the default argument is inserted at the call site. The code you wrote behaves the same as the following code:

    void foo(const std::string& s) {
        // ...
    }
    
    // ...
    
    int main() {
        // ...
        foo("abc");
        // ...
    }
    

    So the std::string temporary is created at the call site.

  2. When the temporary std::string is bound to the const std::string& s, the temporary is lifetime extended. It will live until the end of the complete expression, i.e. the semicolon at the end of foo("abc");.

Putting this together, we can see that s will not dangle, because it points to a temporary string which will live at least as long as foo will execute.

The constructor for std::string(const char*) will be used to construct a temporary that will live for the whole lifetime of the function.

So there will be no problems.

No, the lifetime of the temporary will be extended until the evaluation of the expression containing the call to foo ends. If s scape the function body then it will be a dangling reference.

in standardese [class.temporary]/6.9

A temporary object bound to a reference parameter in a function call (8.2.2) persists until the completion of the full-expression containing the call.

No, the temporary will last until the end of the full expression containing the call to foo, we can see this from the draft C++ standard section [class.temporary]p6 which says:

The third context is when a reference is bound to a temporary object.38 The temporary object to which the reference is bound or the temporary object that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference if the glvalue to which the reference is bound was obtained through one of the following:

...

and then says further down:

The exceptions to this lifetime rule are:
- A temporary object bound to a reference parameter in a function call ([expr.call]) persists until the completion of the full-expression containing the call.

....

which is the case we have here. For a clarification of until the completion of the full-expression see What is the lifetime of a default argument temporary bound to a reference parameter?.

As long as you are not doing something like:

const char* temp;
void foo(const std::string& s = "abc") {
    temp = s.c_str();
}

Or anything like storing a reference to this const ref, you should be fine.

Related