【问题标题】:User-defined literal for stringstream字符串流的用户定义文字
【发布时间】:2021-10-09 15:18:29
【问题描述】:

我写了一个运算符函数,当出现后缀_f 时返回std::stringstream

#include <iostream>
#include <sstream>
#include <utility>

static std::stringstream&& operator "" _f(const char* const s, const size_t _) {
    return std::move(std::stringstream() << s);
}

int main() {
    const auto s = "Number: "_f << 10 << '\n';
    std::cout << s.str();
    return 0;
}

但是,当我运行它时,我得到一个运行时异常:“访问冲突读取位置...”

你能告诉我,我的代码哪里出错了吗?

【问题讨论】:

  • 你的函数返回一个临时的引用。函数一返回,临时对象就被销毁,调用者尝试使用现在悬空的引用,因此程序表现出未定义的行为。
  • 另外,一个人应该很少从一个函数返回引用(而你正是这样做的,而是按值返回)并且一个人几乎不应该return std::move
  • @yeputons C++ 流不能按值传递。它们不支持复制语义,只支持移动语义

标签: c++ c++17 stringstream user-defined-literals


【解决方案1】:

operator 返回对函数内部临时std::stringstream 对象的引用,从而产生悬空引用。你应该直接返回std::stringstream

static std::stringstream operator "" _f(const char* const s, const size_t _) {
    return std::stringstream() << s;
}

【讨论】:

  • 请注意,这只有在编译器使用 RVO(即copy elison)来优化返回时的复制操作时才有效,因为 C++ 流不能被复制,只能移动。
  • 这是一个 C++17 问题,所以我认为复制省略是有保证的。
  • 也许是这样。但是,用户定义的文字是在 C++11 中引入的。用户使用多个 C++ 版本,甚至是实际上没有使用的 C++ 版本来标记问题并不少见,只是为了让更多人关注它们(我不是说这次发生了)。以后有人可能会遇到这个答案,并尝试在不使用复制 elison 的场景中使用它,然后想知道为什么它不起作用。因此我之前的评论。
猜你喜欢
  • 2012-10-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-22
  • 2012-07-19
  • 2020-11-01
  • 2020-11-22
  • 1970-01-01
相关资源
最近更新 更多