c++ - I/O 操纵器错误或 const ref 的临时生命周期延长?

标签 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 行可能是错误的,因为在流式传输自定义对象时引用无效(即,我的 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 type moneyT shall be either long double or a specialization of the basic_string template.

Returns: An object of unspecified type such that if out is an object of type basic_ostream then the expression out << put_money(mon, intl) behaves as a formatted output function that calls f(out, mon, intl), where the function f is defined as:

[ example omitted ]

The expression out << put_money(mon, intl) shall have type basic_ostream& and value out.

它的长短是std::put_money仅当它位于 << 的右侧时才定义格式化输出运算符,左侧为 std::basic_ostream .只有您的第 2 行符合该要求,而第 1 行不符合。

关于c++ - I/O 操纵器错误或 const ref 的临时生命周期延长?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57517690/

相关文章:

c++ - 如何判断哪个类拥有指针

ios - 防止 NSManagedObject 引用更新 UITableViewCell

c++ - 为什么将 const std::string& 传递给构造函数不允许将其绑定(bind)到初始化列表中的 const std::string& 成员变量?

c# - 为什么在 using 语句中声明的变量被视为只读?

.net - AppDomain 仅部分尊重InitializeLifetimeService(如果有的话)

android - 无法为不是由该项目构建的目标指定链接库

c++ - 多个输入验证约束? C++

c++ - 无向图中的路径查找

c++ - 构造函数中的 const int ref 可以安全地绑定(bind)到文字吗?

c++ - 这些本地函数的返回地址之间有什么区别?