I/O 操纵器错误或临时延长寿命由 const 参考?

I/O manipulator bug or temporary lifetime extension by const ref?

本文关键字:const 参考 时延 操纵 错误      更新时间:2023-10-16

我试图包装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 行可能是错误的,因为在流式传输自定义对象时引用无效(即,scale在我的acm::put_money中返回的临时值已被破坏(。

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

理论1:"运气不好。 保留对临时的 const 引用是一个错误,但碰巧该值仍然存在于堆栈上,可能是因为它没有被额外的函数调用践踏。 (发布版本通常有效这一事实支持这一点,大概是因为额外的函数调用是内联的。

理论 2:通过 const 引用延长临时的寿命在第二种情况下有所帮助,但由于某种原因,它不适用于第一种情况。 也许额外的函数调用违反了延长寿命的规则?

理论3:???

最后位于标准中指定的位置(为了可读性而略微编辑(:

[分机]

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

Requires:moneyT型应为长双 或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 行不符合。