如果使用默认参数初始化一个const引用参数,会导致悬空引用吗?

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

// ...

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

foo 中的 s 会成为悬空指针吗?我认为是因为 std::string 将从默认值 "abc" 构造,然后这将是一个 const 引用到已死临时对象。

我的理解正确吗?

5个回答

6

s不会在foo中挂起,但是临时变量将在整个foo生存期内存在。理解为什么会发生这种情况需要理解一些要点:

  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");.

综合起来,我们可以看到s不会悬空,因为它指向一个临时字符串,该字符串将至少在foo执行期间存在。


5

构造函数std::string(const char*)将被用于构造一个临时对象,该对象将在整个函数的生命周期内存在。

因此不会出现任何问题。


3
不,临时对象的寿命将延长到包含对foo调用的表达式求值结束为止。如果s超出函数体范围,则它将成为悬空引用。
在标准中,一个绑定到函数调用(8.2.2)中的引用参数的临时对象会一直存在,直到包含该调用的完整表达式被计算完成。[class.temporary]/6.9

请注意,当您说“直到调用foo返回”时,并不意味着“包含该调用的完整表达式已完成”。 - Shafik Yaghmour
是的,你说得对,我已经修正了答案中的措辞。 - Jans

1
不,临时对象的寿命将持续到包含对foo调用的完整表达式的结尾,我们可以从C++标准草案第[class.temporary]p6节中看出这一点,该节说:

第三种情况是当引用绑定到临时对象时。38 如果引用绑定的glvalue是通过以下方式之一获得的,则引用绑定的临时对象或作为引用绑定的子对象的完整对象将在引用的生命周期内保留:

...

然后进一步说明:

此寿命规则的例外情况有:
- 在函数调用([expr.call])中绑定到引用参数的临时对象将持续到包含调用的完整表达式完成。

....

这就是我们现在所面临的情况。关于“直到完整表达式完成”的澄清,请参见What is the lifetime of a default argument temporary bound to a reference parameter?


0
只要你不做像这样的事情:
const char* temp;
void foo(const std::string& s = "abc") {
    temp = s.c_str();
}

或者像存储对这个常量引用的引用之类的任何事情,你都应该没问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接