在C ++中使用临时对象作为默认参数是否安全?

时间:2012-07-20 01:01:04

标签: c++ language-lawyer

例如:

int StrLen(const std::string &s = "default string") {
  const std::string &t = "another string";  // BTW, is this line safe?
  return s.size();
}

更新

SoapBox的结论是正确的,但原因并不完全正确。

  

临时的生命周期自动扩展为相同   作为持有它的参考。

通常有几个例外。一个是那个

  

“临时绑定到函数调用中的引用参数   一直持续到包含完整表达式的完整表达式   呼叫“。

我认为此例外适用于默认参数案例。

另一个例外与SoapBox的答案中的附加示例有关:

  

“函数中返回值临时绑定的生命周期   return语句没有扩展;临时被摧毁了   返回语句中的完整表达式的结尾。“

3 个答案:

答案 0 :(得分:5)

是的,这两件事都是安全的。它们构造临时对象,临时对象的生命周期自动扩展为与持有它的引用相同。

虽然我们谈论的是这个问题,但这是一个常见的错误,因为临时工作安全。

std::string const &accessor() const {
    if (my_name_is_valid())
        return m_my_name;
    else
        return "";
}

这是无效的,因为临时是在accessor函数内创建的,然后返回引用。调用者将收到对被破坏对象的引用...这是未定义的行为,通常会导致崩溃。

答案 1 :(得分:3)

SoapBox的答案是正确的,但是并不总是很明显这些限制是什么。

  

通常有几个例外。一个是“函数调用中的参考参数的临时绑定持续到包含调用的完整表达式完成为止。”我认为这个例外适用于默认参数情况。

虽然有时以微妙的方式,但确实考虑了以下两个例子:

struct A { A(std::string const& s): _ref(s) {} std::string const& _ref; };

struct B { B(std::string s): _ref(s) {} std::string const& _ref; };

在这两个例子中,函数都是构造函数。

  • A中:临时的生命周期延长到完整表达式结束意味着A a("Hello"); std::cout << a._ref << "\n";不安全。临时只生活到第一个;
  • B中:参数本身是临时的,这里根本没有绑定到const-reference 。一个好的编译器会警告。
  

另一个例外与SoapBox的答案中的另一个例子有关:“函数返回语句中返回值临时绑定的生命周期未被扩展;临时值在返回的完整表达式结束时被销毁语句“。

这一点源于return语句一般的工作方式。就标准而言,下面有两份副本正在进行中。那就是:

  1. 调用return会将结果复制到“结果槽”
  2. 如果有的话,调用者会将“结果槽”中的值复制到其存储空间中。
  3. 当然,副本可以被优化掉(复制省略),但这很重要,因为临时的生命周期只会延伸到它所绑定的原始 const-reference。如果该引用的副本超过了原始的生命周期,则它引用垃圾,这就是return语句中发生的情况。

答案 2 :(得分:-3)

是。该字符串被分配为静态文本,不会移动或更改。