8
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?

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
vladon
  • 8,158
  • 2
  • 47
  • 91

5 Answers5

6

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.

Justin
  • 24,288
  • 12
  • 92
  • 142
5

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.

RedX
  • 14,749
  • 1
  • 53
  • 76
3

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.

Jans
  • 11,064
  • 3
  • 37
  • 45
1

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?.

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
0

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.

Matthieu Brucher
  • 21,634
  • 7
  • 38
  • 62