I / O机械手错误或由const ref临时延长生命周期?

时间:2019-08-16 00:39:05

标签: c++ reference object-lifetime iomanip

我试图包装io机械手std::put_money。这是一个简化的插图:

#include <iomanip>
#include <iostream>

long double scale(long double f) { return f * 100.0L; }

namespace acm {

auto put_money(const long double &f, bool intl = false) {
  return std::put_money(scale(f), intl);
}

}

int main() {
  long double f(1234.567L);
  std::cout << "1: " << acm::put_money(f) << '\n';
  std::cout << "2: " << std::put_money(scale(f)) << '\n';
  return 0;
}

输出为:

1: -92559631349317829570406876446720000000000000000000000000000000
2: 123457

我研究了MSVC和libc ++的原理,得知std::put_money返回了一个自定义类型,该类型保留对该值的const引用,而不是进行复制。

第1行可能是错误的,因为流式传输自定义对象时引用无效(即scaleacm::put_money返回的临时值已被破坏)。

问:但是,为什么第二行是正确的?

理论1:“运气不好”。保持对临时变量的const引用是一个错误,但是恰好碰巧该值仍然存在于堆栈中,可能是因为该值并未被额外的函数调用所破坏。 (这是因为Release版本通常可以正常工作的事实,大概是因为内联了额外的函数调用。)

理论2:在第二种情况下,通过const引用对临时目录进行终生扩展是有帮助的,但是由于某种原因,它不适用于第一种情况。也许额外的函数调用违反了生命周期延长的规则?

理论3:???

1 个答案:

答案 0 :(得分:0)

最终位于标准中指定的位置(为便于阅读,对其进行了略微编辑):

  

[ext.manip]

     

template <class moneyT> unspecified put_money(const moneyT& mon, bool intl = false);

     

Requires:类型moneyT可以是long double   或basic_string模板的特殊化。

     

Returns:未指定类型的对象,例如,如果out是类型的对象   basic_ostream然后是表达式out << put_money(mon, intl)   表现为调用的格式化输出函数   f(out, mon, intl),其中功能f定义为:

     

[示例省略]

     

表达式out << put_money(mon, intl)的类型应为   basic_ostream&和值out

长短之处在于std::put_money仅在<<格式的输出运算符的右侧且左侧为std::basic_ostream的情况下定义。仅您的第2行符合该要求,而第1行则不满足。