是否可以通过const引用返回默认参数的值?


26

是否可以通过const引用返回默认参数的值,如以下示例所示:

https://coliru.stacked-crooked.com/a/ff76e060a007723b

#include <string>

const std::string& foo(const std::string& s = std::string(""))
{
    return s;
}

int main()
{
    const std::string& s1 = foo();
    std::string s2 = foo();

    const std::string& s3 = foo("s");
    std::string s4 = foo("s");
}

3
简单测试:用std::string您自己的一类替换,这样您就可以跟踪构造和破坏。
— user4581301

1
@ user4581301如果序列正确,则不能证明该构造是正确的。
— 彼得-恢复莫妮卡

6
@ user4581301“当我尝试时它似乎起作用”是关于未定义行为的绝对最糟糕的事情
— HerrJoebob,

应当指出的是,这个问题在措词上是一种误导。您不是通过const引用返回默认参数的值,而是将const引用返回到const引用(...到默认参数)。
— 戴蒙

2
@HerrJoebob同意语句100%,但不同意您使用它的上下文。我的阅读方式是,这个问题解决为“对象的生命周期何时结束?” 确定何时调用析构函数是一种很好的方法。对于自动变量,应该及时调用析构函数,否则您将遇到很多问题。
— user4581301

Answers:


18

在您的代码中,s1和s3都是悬空的引用。s2而且s4还可以。

在第一个调用中,std::string将从默认参数创建的临时空对象创建在包含该调用的表达式的上下文中。因此,它将在的定义的末尾死掉s1,从而s1悬而未决。

在第二个调用中,临时std::string对象用于初始化s2,然后死亡。

在第三个调用中,字符串文字"s"用于创建一个临时std::string对象,该对象也死于的定义的末尾s3,保持s3悬空状态。

在第四次调用中,std::string带有值的临时对象"s"用于初始化s4,然后死亡。

参见C ++ 17 [class.temporary] /6.1

绑定到函数调用(8.2.2)中的参考参数的临时对象将一直存在,直到包含该调用的完整表达式完成。


1
答案的有趣部分是断言默认参数将在调用者的上下文中创建。纪尧姆的标准报价似乎支持了这一点。
— 彼得-恢复莫妮卡

2
@ Peter-ReinstateMonica参见[expr.call] / 4,“ ...每个参数的初始化和销毁​​均在调用函数的上下文内发生。...”
— Brian

8

这是不安全的:

通常,不能通过“传递”来进一步延长临时项的生存期:从临时项所绑定到的引用初始化的第二个引用不影响其生存期。


那么,您认为std::string s2 = foo();有效吗(毕竟,没有明确传递任何引用)?
— 彼得-恢复莫妮卡

1
@ Peter-ReinstateMonica会很安全,因为将构造新对象。我的答案仅仅是关于终身扩展。其他两个答案已经涵盖了所有内容。我不会重复我的。
— 遗忘

5

这取决于您随后对字符串的处理方式。

如果您的问题是我的代码正确吗?那是的

从[dcl.fct.default] / 2开始

[ 示例:声明

void point(int = 3, int = 4);

声明一个可以用零,一或两个int类型的参数调用的函数。可以通过以下任何一种方式调用它:

point(1,2);  point(1);  point();

最后两个调用分别等效于point(1,4)和point(3,4)。— 结束示例 ]

因此,您的代码实际上等效于:

const std::string& s1 = foo(std::string(""));
std::string s2 = foo(std::string(""));

您的所有代码都是正确的,但是在任何情况下都没有引用生存期的延长,因为返回类型是引用。

由于您使用临时函数调用函数,因此返回的字符串的生存期不会延长该语句。

const std::string& s1 = foo(std::string("")); // okay

s1; // not okay, s1 is dead. s1 is the temporary.

您的示例s2可以使用,因为您可以在地块结束之前从临时位置复制(或移动)。s3与...有同样的问题s1。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.