我试图包装 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 行可能是错误的,因为在流式传输自定义对象时引用无效(即,我的 acm::put_money
中的 scale
返回的临时值已经毁)。
问:但是,为什么第 2 行是正确的?
理论 1:“运气不好”。保持对临时对象的 const 引用是一个错误,但碰巧该值仍然存在于堆栈中,可能是因为它没有被额外的函数调用践踏。 (发布版本通常可以正常工作这一事实支持了这一点,大概是因为额外的函数调用是内联的。)
理论 2:const 引用对临时对象的生命周期延长在第二种情况下有所帮助,但由于某种原因,它不适用于第一种情况。也许额外的函数调用打破了生命周期延长的规则?
理论 3:???
最佳答案
最终位于标准中指定的位置(为了便于阅读而稍作编辑):
[ext.manip]
template <class moneyT> unspecified put_money(const moneyT& mon, bool intl = false);
Requires:
The typemoneyT
shall be either long double or a specialization of thebasic_string
template.
Returns:
An object of unspecified type such that if out is an object of type basic_ostream then the expressionout << put_money(mon, intl)
behaves as a formatted output function that callsf(out, mon, intl)
, where the functionf
is defined as:[ example omitted ]
The expression
out << put_money(mon, intl)
shall have type basic_ostream& and valueout
.
它的长短是std::put_money
仅当它位于 <<
的右侧时才定义格式化输出运算符,左侧为 std::basic_ostream
.只有您的第 2 行符合该要求,而第 1 行不符合。
关于c++ - I/O 操纵器错误或 const ref 的临时生命周期延长?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57517690/