554

我已经尝试了几件事,

std::stringstream m;
m.empty();
m.clear();

两者都不起作用。

4

9 回答 9

866

对于所有标准库类型,成员函数empty()是一个查询,而不是一个命令,即它的意思是“你是空的吗?” 不是“请扔掉你的东西”。

clear()成员函数继承自ios并用于清除流的错误状态,例如,如果文件流的错误状态设置为(eofbit文件结束),则调用clear()会将错误状态设置回goodbit(无错误) .

要清除 a 的内容stringstream,请使用:

m.str("");

是正确的,虽然使用:

m.str(std::string());

在技​​术上更有效,因为您避免调用std::string采用const char*. 但是现在任何编译器都应该能够在这两种情况下生成相同的代码——所以我会选择更具可读性的代码。

于 2008-08-21T19:00:25.143 回答
61

您可以在一行中清除错误状态清空字符串流

std::stringstream().swap(m); // swap m with a default constructed stringstream

这有效地将 m 重置为默认构造状态,这意味着它实际上删除了字符串流分配的缓冲区并重置错误状态。这是一个实验证明:

int main ()
{
    std::string payload(16, 'x');
    
    std::stringstream *ss = new std::stringstream; // Create a memory leak
    (*ss) << payload;                              // Leak more memory
    
    // Now choose a way to "clear" a string stream
    //std::stringstream().swap(*ss); // Method 1
    //ss->str(std::string());        // Method 2
    
    std::cout << "end" << std::endl;
}

演示

当使用地址清理程序编译演示时,会显示内存使用情况:

=================================================================
==10415==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 392 byte(s) in 1 object(s) allocated from:
    #0 0x510ae8 in operator new(unsigned long) (/tmp/1637178326.0089633/a.out+0x510ae8)
    #1 0x514e80 in main (/tmp/1637178326.0089633/a.out+0x514e80)
    #2 0x7f3079ffb82f in __libc_start_main /build/glibc-Cl5G7W/glibc-2.23/csu/../csu/libc-start.c:291

Indirect leak of 513 byte(s) in 1 object(s) allocated from:
    #0 0x510ae8 in operator new(unsigned long) (/tmp/1637178326.0089633/a.out+0x510ae8)
    #1 0x7f307b03a25c in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::reserve(unsigned long) (/usr/local/lib64/libstdc++.so.6+0x13725c)
    #2 0x603000000010  (<unknown module>)

SUMMARY: AddressSanitizer: 905 byte(s) leaked in 2 allocation(s).

如果你问我,那就太陡了。为了只保存 16 字节的有效负载,我们花费了 905 字节……字符串流不是玩具。内存分配分为两部分:

  • 构造的字符串流(392字节)
  • 有效负载所需的额外缓冲区(513 字节)。无关大小与流选择的分配策略有关,对于 <= 8 字节的有效负载,可以使用初始对象内的块。

如果启用方法 1(此答案中显示的方法),则会回收额外的 513(有效负载)字节,因为流实际上已清除

如果您按照评论或其他答案中的建议启用 method2,您可以看到在我们退出时所有 905 个字节都在使用中。

在程序语义方面,人们可能只关心流“出现”和“表现”为空,类似于 avector::clear可能保持容量不变但向用户呈现向量为空(当然向量在这里只花费 16 个字节) )。鉴于字符串流所需的内存分配,我可以想象这种方法通常更快。这个答案的主要目标是真正清除字符串流,因为它带来的内存消耗不是开玩笑的。根据您的用例(流的数量、它们持有的数据、清除频率),您可以选择最佳方法。

最后请注意,在不清除错误状态和所有继承状态的情况下清除流很少有用。这个答案中的一个衬里两者兼而有之。

于 2014-04-24T10:34:52.740 回答
38
m.str("");

似乎工作。

于 2008-08-21T18:36:18.493 回答
37

无论编译器如何,这应该是最可靠的方法:

m=std::stringstream();
于 2012-10-11T16:00:12.300 回答
13

我总是在范围内:

{
    std::stringstream ss;
    ss << "what";
}

{
    std::stringstream ss;
    ss << "the";
}

{
    std::stringstream ss;
    ss << "heck";
}
于 2014-03-26T17:37:19.057 回答
12

我的 2 美分:

这似乎在 xcode 和 dev-c++ 中对我有用,我有一个菜单形式的程序,如果根据用户的请求迭代执行,它将填充一个 stringstream 变量,该变量在第一次代码时可以正常工作运行但不会在用户下次运行相同的代码时清除字符串流。但是下面的两行代码最终在每次填充字符串变量之前都清除了字符串流变量。(2 小时的反复试验和谷歌搜索),顺便说一句,单独使用每一行是行不通的。

//clear the stringstream variable

sstm.str("");
sstm.clear();

//fill up the streamstream variable
sstm << "crap" << "morecrap";
于 2013-10-18T00:34:05.900 回答
1

还有许多其他“有效”的答案,但它们经常做不必要的复制或重新分配内存。

  1. 交换流意味着您需要丢弃其中一个,浪费内存分配。分配默认构造的流也是如此,

  2. 分配给字符串缓冲区中的字符串(通过stringstream::strstringbuf::str)可能会丢失字符串已经分配的缓冲区。

清除字符串流的规范方法是:

void clear(std::stringstream &stream)
{
   if (stream.rdbuf()) stream.rdbuf()->pubseekpos(0);
}

获取流缓冲区中数据大小的规范方法是:

std::size_t availSize() (const std::stringstream& stream)
{
   if (stream.rdbuf())
      return std::size_t(
         stream.rdbuf()->pubseekoff(0, std::ios_base::cur, std::ios_base::out));
   else
      return 0;
}

将数据从流复制到其他一些预先分配的缓冲区然后清除它的规范方法是:

std::size_t readAndClear(std::stringstream &stream, void* outBuf, std::size_t outSize)
{
   auto const copySize = std::min(availSize(stream), outSize);
   if (!copySize) return 0; // takes care of null stream.rdbuf()

   stream.rdbuf()->sgetn(outBuf, copySize);
   stream.rdbuf()->pubseekpos(0); // clear the buffer

   return copySize;
}

我打算这是一个规范的答案。语言律师,请随时参与。

于 2021-09-13T14:23:10.540 回答
-1

这是一个概念问题。

Stringstream 是一个流,所以它的迭代器是向前的,不能返回。在输出字符串流中,您需要一个 flush() 来重新初始化它,就像在任何其他输出流中一样。

于 2014-10-10T20:04:50.397 回答
-14

这些不会丢弃 gnu c++ 中字符串流中的数据

    m.str("");
    m.str() = "";
    m.str(std::string());

以下确实为我清空了字符串流:

    m.str().clear();
于 2012-09-06T22:58:41.527 回答