字符串流有啥意义? [复制]

Posted

技术标签:

【中文标题】字符串流有啥意义? [复制]【英文标题】:What's the point of stringstream? [duplicate]字符串流有什么意义? [复制] 【发布时间】:2016-05-31 18:24:02 【问题描述】:

我将保持这个问题非常简单。我正在学习 C++,并且遇到过字符串流。我知道它们的主要用途是将变量输入到它们中,以便它们以后可以使用 str() 作为字符串输出它们保存的值。我的问题是——这有什么意义?这听起来像是一种非常奇特的方式,只需使用 + 运算符连接字符串对象中的一堆变量。它是否有更多的意义,或者它只是让新手感到困惑并导致他们考试不及格?

【问题讨论】:

实用性的完美示例:***.com/questions/236129/split-a-string-in-c 所以它就像连接,除了它还跟踪输入的变量? 它也可以用于取消连接字符串。 太棒了,谢谢!我可以给你点赞吗? 不,但您确实有几个答案可以考虑支持或接受。 【参考方案1】:

嗯,一个问题是您不能“使用 + 运算符连接字符串中的一堆变量”(仅适用于其他字符串或 char*s)。

那么,您将如何将所有对象转换为字符串?与 Java 不同,C++ 没有任何 to_string() 成员约定。另一方面,每个对使用 iostream 感兴趣的类都会定义流插入器(std::ostream& operator<<(std::ostream& os, const MyClass& foo) 可能还有std::istream& operator>>(std::istream& os, MyClass& foo)。)

因此,您使用流插入器将对象转换为文本。有时您不想写入控制台或文件,而是想将其存储为字符串。

此外,使用 iostream 框架可以让您使用操纵器来控制精度、宽度、数字基数等,而不是在构建字符串时尝试手动完成所有这些操作。

现在,这并不是说 stringstream 解决方案是理想的:事实上,存在许多库可以更好地完成相同类型的任务(至少包括 Boost.Format、Boost.Convert、Boost.Lexical_Cast 和 Boost .Spirit 就在 Boost 中。)

【讨论】:

“C++ 没有任何 to_string() 成员约定。” 好吧,那不是entirely true。 @πάνταῥεῖ:“成员”是指在您定义的所有类中创建to_string() 成员函数不是标准的,标准库不会尝试使用此类函数。标准库中存在名为to_string 的函数这一事实并不是真正相关的。您可以为您的类声明免费的 to_string 函数,以便通过 ADL 通用地使用,但 AFAIK 这也不是一个约定——最好使用 boost::lexical_cast 来处理这类事情。 嗯,boost就是boost,c++标准就是c++标准。【参考方案2】:

如果你有:

int a = 3;
std::string str = "hello";
MyObject obj;

然后:

std::string concat = a + str + obj;
std::string objstr = obj; 

不起作用,而:

std::stringstream stream;
stream << a << str << obj;
std::string concat = stream.str();

std::stringstream stream2;
stream2 << obj;
std::string objstr = stream2.str();

会起作用(至少如果MyObject 定义了operator&lt;&lt;)。这就是std::stringstream 的全部意义所在:使将“任何东西”重定向到字符串变得容易。

任何可以重定向到std::ostreamstd::fstreamstd::cout...)的对象也可以重定向到std:::stringstream(因为它也派生自̀std::ostream)。然后你只需要声明一个std::ostream 重定向操作符(operator&lt;&lt;),它就可以用来在任何地方重定向对象(文件,控制台,还有字符串......)。

重点是您可以声明operator+operator+=,以便将您的对象连接到std::string。但是,如果您还希望将其重定向到流(文件、cout),则必须声明 3 个运算符(operator+operator+=,最后是 operator&lt;&lt; 用于流),它们几乎都在做同样的事情.最后,感谢std::stringstream,只有一个运算符(operator&lt;&lt;)就足以重定向到文件、cout 和字符串。

【讨论】:

通过可变参数模板,我们可以拥有一个函数,该函数使用该代码与任意数量的元素,并轻松调用它以将任意数量的任何类型的参数连接成一个字符串。 所以它在某些方面类似于Java中的toString()? operator&lt;&lt; 类似于 toString()。 ̀std::stringstream` 可以将 ̀std::string` 用作目标。【参考方案3】:

stringstream 的意义何在?

它是一种灵活且快速的流,可作为其他(相对)慢速流的模拟器。我将 stringstream 用于许多不同的事情。


我最喜欢的用途是测试。我创建了一个 std::istream 并用测试数据填充它。这使我可以使用与我编码相同的编辑器创建测试数据“文件”(并且没有实际文件污染我的工作目录)。添加更多测试用例的耗时明显减少。

   //                      012345678901234567890123456789012345678901234567890
   std::istringstream iss("7 ((23, 342), (17, 234), (335, 159), (10, 10))");
   //                      ---|^^^^^^^|^v|vvvvvvv|v^|^^^^^^^^|^v|vvvvvv|^
   //                         1         2          3           4

   // echo to user of test
   std::cout << "Test Data Input: " << iss.str() << std::endl ;

   // code under test starts here ... 
   int    nTowns = 1;
   char  lparen0 = 2;
   iss >> nTowns       // NOTE : formatted input drops whitespace
       >> lparen0;

   // and continues with echo of post conversion
   std::cout << " 0: " << nTowns << ' ' << lparen0 << std::endl;

   // then more of the same - until record is completely read.

我已经使用 stringstream 来构建屏幕更新,并使用该动态变化的字符串来“测量”横幅宽度,并计算在屏幕上开始放置的位置,以便横幅居中(或左侧或右侧) :

static void centerUpdateScreenBanner( uint64_t gen, 
                                      int      pdMS, 
                                      int      changes, 
                                      TC_t&    tc)
  
     // build contents of screen banner update
     std::stringstream ss;
     ss << std::setw(3) << pdMS << "  "
        << std::setw(4) << gen  << "  "
        << std::setw(4) << changes;

     // compute start column placement for centering
     int rCol = tc.maxCol - 
                static_cast<int>(ss.str().size()) +
                tc.DfltIndnt-1;

     // send banner to terminal device for user info
     tc.termRef << Ansi_t::gotoRC(0, rCol)  // top right
                << ss.str() << std::flush;
  

在这个链接列表中,我使用一个字符串流来吸收和递归连接列表节点信息。虽然这是递归构建的,但其他 cout 或 cerr 可以不受阻碍地继续进行 - 就像第三个通道一样。

  std::string showR(void) 
     std::stringstream ss;
     ss << m_payload->show();            // this node
     if(m_next)  ss << m_next->showR();  // subsequent nodes
     return (ss.str());
  

总结:我发现 std::stringstream 非常有用。

【讨论】:

以上是关于字符串流有啥意义? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

如何清除字符串流中的内容。? [复制]

获取字符串流中的最后一个字符而不复制其整个缓冲区

memorystream - 字符串流,字符串,其他?

C++ 字符串流

istringstream sin(s); 这个语句是啥意思

字符串流