【问题标题】:Want ostringstream to modify passed string想要 ostringstream 修改传递的字符串
【发布时间】:2015-03-12 18:04:26
【问题描述】:

我想std::ostringstream 修改我传递给它的字符串:

#include <string>
#include <iostream>
#include <sstream>

void My_Function(std::string& error_message)
{
  std::ostringstream error_stream(error_message);
  // For Nipun Talukdar:
  /* Perform some operations */
  if (/* operation failed */)
  {
      error_stream << "Failure at line: "
                   << __LINE__
                   << ", in source file: "
                   << __FILE__
                   << "\n";
  }
  return;
}

int main(void)
{
  std::string error_message;
  My_Function(error_message);
  std::cout << "Error is: \""
            << error_message
            << "\"\n";
  return 0;
}

使用上面的代码,error_message 的输出为空。

这是因为,according to cppreference.com,采用 std::streamstd::basic_ostream 的构造函数采用 conststd::string 的引用。这意味着std::basic_ostringstream 不会修改传递给它的字符串。引用的参考文献甚至说std::ostringstream 制作了传递给它的字符串的副本

为了解决这个问题,我改变了我的功能:

void My_Second_Function(std::string& error_message)
{
  std::ostringstream error_stream;
  error_stream << "Failure at line: "
               << __LINE__
               << "\n";
  error_message = error_stream.str();  // This is not efficient, making a copy!
  return;
}

是否有更有效的方法来执行格式化输出到字符串,例如直接写入(即无需从流中复制)?

我使用的是 Visual Studio 2010,不支持 C++11。由于店铺考虑,升级到2013年的理由没有通过。所以我不能使用 C++11 或 C++14 的特性。

【问题讨论】:

  • 使用流缓冲区并相应地设置放置指针。
  • 与问题无关,但它不会总是打印相同的行号吗?
  • @NipunTalukdar:__LINE__ 宏返回源代码中的行号。如果在__LINE__ 宏的位置之前插入或删除代码,行号可能会改变。
  • @0x499602D2:请提供包含您评论示例的答案。谢谢。
  • @ThomasMatthews 是的。但它总是会在 My_Function 中打印相同的行号。因此,每次调用 My_Function 都会输出相同的行号。

标签: c++ string visual-studio-2010 c++03 ostringstream


【解决方案1】:

使用流缓冲区并将 put 指针设置为字符串的内部数据:

struct nocopy : std::streambuf
{
    nocopy(std::string& str)
    { this->setp(&str[0], &str[0] + str.size()); }
};

struct nocopy_stream : virtual private nocopy, std::ostream
{
    nocopy_stream(std::string& str)
        : nocopy(str)
        , std::ostream(this)
    { }
};

void My_Function(std::string& error_message)
{
  nocopy_stream error_stream(error_message);
  error_stream << "Failure at line: "
               << __LINE__
               << "\n";
}

int main(void)
{
  std::string error_message;
  error_message.resize(1000);

  My_Function(error_message);
  std::cout << "Error is: \""
            << error_message
            << "\"\n";
}

对于此示例,error_message 必须设置为足够大的大小,因为我们不会覆盖 overflow(),并且基类版本什么也不做。但是,您可以覆盖它以进行正确的调整大小。

【讨论】:

  • 它的意义远不止于此。您的 streambuf 不会改变它给出的字符串的大小;如果你输出更多,那么只会有一个输出错误,如果你输出更少,最后会有很多垃圾。 (当然,整个问题是似是而非的。无论你怎么做,肯定会有一些抄袭;另一方面,与其他一切相比,抄袭的成本应该可以忽略不计。)
  • @JamesKanze 当然,这比这更重要。或许你能给出充分的答案?
  • @JamesKanze, @0x499602D2:那么,为什么ostringstream 会复制您传递给它的字符串?
  • @ThomasMatthews:这实际上是一个非常好的问题。 R.Sahu 建议它用于附加,但我认为这只是疏忽。
  • @ThomasMatthews 因为这就是它的定义。根本原因是std::stringbuf不知道是用于输入还是输出;如果是输入,它从你给它的字符串中读取。一个更合乎逻辑的解决方案可能是根本没有std::stringstream 类,并有两个不同的字符串缓冲区,一个用于输入,一个用于输出。然而,IO 流的理念始终是支持双向流,即使我们现在知道它们的用途有限。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-30
  • 2011-10-18
相关资源
最近更新 更多