如何清除字符串流变量?
Posted
技术标签:
【中文标题】如何清除字符串流变量?【英文标题】:How do you clear a stringstream variable? 【发布时间】:2010-09-06 10:48:56 【问题描述】:我已经尝试了几件事,
std::stringstream m;
m.empty();
m.clear();
这两个都不行。
【问题讨论】:
【参考方案1】:对于所有标准库类型,成员函数empty()
是一个查询,而不是一个命令,即它的意思是“你是空的吗?”而不是“请扔掉你的东西”。
clear()
成员函数继承自ios
,用于清除流的错误状态,例如如果文件流的错误状态设置为eofbit
(文件结束),则调用clear()
会将错误状态设置回goodbit
(无错误)。
要清除stringstream
的内容,请使用:
m.str("");
是正确的,虽然使用:
m.str(std::string());
在技术上更有效,因为您避免调用采用const char*
的std::string
构造函数。但是现在任何编译器都应该能够在这两种情况下生成相同的代码 - 所以我会选择更具可读性的代码。
【讨论】:
当您忘记“clear()”部分时会发生以下情况。 ***.com/q/2848087/635549 @KshitijBanerjee 我认为在 C++ 中 m.str() 和 m.str("") 是两个不同的函数。 m.str() 调用一个不期望任何参数的函数,而 m.str("") 将调用接受 const char* 参数的函数。 m.str() 可能已实现为返回字符串的 get 函数,而 m.str("") 可能已实现为 set 函数。跨度> 正如 galath 所说,添加 m.clear(); 也很重要。除了 m.str("");。否则,如果在某些时候用空字符串填充字符串流,您可能会遇到问题。 @anthropod 是的,那是去年。我已经让它工作了。 天哪,这太直观了。就像其他关于 C++ 的一切一样!【参考方案2】:您可以在一行中清除错误状态和清空字符串流
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;
Demo
当使用地址清理程序编译演示时,会显示内存使用情况:
=================================================================
==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 字节)。无关大小与流选择的分配策略有关,对于如果您enable method 1(此答案中显示的那个),则回收额外的 513(有效负载)字节,因为流实际上已清除。
如果您按照 cmets 或其他答案中的建议enable method2,您可以看到在我们退出时所有 905 个字节都在使用中。
就程序语义而言,人们可能只关心流“出现”和“表现”为空,类似于vector::clear
可能保持容量不变但将向量呈现为空给用户(当然向量将只在这里花费 16 个字节)。鉴于字符串流所需的内存分配,我可以想象这种方法通常更快。 这个答案的主要目标是真正清除字符串流,因为它带来的内存消耗不是开玩笑。根据您的用例(流的数量、它们持有的数据、清除频率),您可以选择最佳方法。
最后请注意,在不清除错误状态和所有继承状态的情况下清除流很少有用。这个答案中的一个班轮兼而有之。
【讨论】:
与此处的所有其他答案相比,这是最有效和最优雅的方法。但是,std::stringstream::swap 是 c++11 的一个特性,这个解决方案不适用于之前的 c++11 编译器。 GNU g++ v4.8 中仍然缺少功能,请参阅***.com/questions/24429441/… @101010:交换比移动分配更好吗? @AsetD:就算是noexcept,你是不是忘记了默认构造的临时? 这是低效率的。当我想重新使用原始ss时。它为我换了一个空的。【参考方案3】:m.str("");
似乎有效。
【讨论】:
这将被 .clear() 清除,它在 OP 中指定。【参考方案4】:无论编译器如何,这应该是最可靠的方法:
m=std::stringstream();
【讨论】:
我认为这更好,因为 m.str("");无论我尝试什么,都会导致我的字符串流被那个空值卡住。但是使用这个我没有那个问题 我遇到了同样的问题,对我来说mm.clear(); mm.str("");
成功了。 (没有 C++11,否则交换会更好)。
@hochl:为什么swap
比 move-assignment 更好?
这并不适用于所有情况。这将每次重新分配缓冲区,而 mm.str("") 不会。
我刷新字符串流对象的主要用例是保留一个线程本地字符串流对象,以防止不必要的字符串流实例化——实例化一个新的字符串流对象复制全局语言环境对象——理论上这很快并且只涉及增加一个原子,但在并发级别上,我处理它通常很严重。【参考方案5】:
我总是在范围内:
std::stringstream ss;
ss << "what";
std::stringstream ss;
ss << "the";
std::stringstream ss;
ss << "heck";
【讨论】:
这比清除stringstream?
好吗【参考方案6】:
我的 2 美分:
这似乎在 xcode 和 dev-c++ 中对我有用,我有一个菜单形式的程序,如果根据用户的请求迭代执行,它将填充一个 stringstream 变量,该变量第一次可以正常工作该代码将运行,但不会在用户下次运行相同的代码时清除字符串流。但是下面的两行代码最终在每次填充字符串变量之前都清除了字符串流变量。 (2 小时的反复试验和谷歌搜索),顺便说一句,单独使用每一行是行不通的。
//clear the stringstream variable
sstm.str("");
sstm.clear();
//fill up the streamstream variable
sstm << "crap" << "morecrap";
【讨论】:
【参考方案7】:还有许多其他“有效”的答案,但它们通常会进行不必要的复制或重新分配内存。
交换流意味着您需要丢弃其中一个,浪费内存分配。分配默认构造的流也是如此,
分配给字符串缓冲区中的字符串(通过stringstream::str
或stringbuf::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;
我希望这是一个规范的答案。语言律师,请随时参与。
【讨论】:
【参考方案8】:这是一个概念问题。
Stringstream 是一个流,所以它的迭代器是向前的,不能返回。在输出字符串流中,您需要一个 flush() 来重新初始化它,就像在任何其他输出流中一样。
【讨论】:
en.cppreference.com/w/cpp/io/basic_ostream/flush flush 与其关联的存储设备同步。这不是相同的重新初始化。【参考方案9】:这些不会丢弃gnu c++中stringstream中的数据
m.str("");
m.str() = "";
m.str(std::string());
以下内容确实为我清空了字符串流:
m.str().clear();
【讨论】:
我不太确定这会起作用,因为与 bernhardrusch 不起作用的原因相同。 .str() 函数返回一个副本,清除副本不会做任何事情。 此解决方案不适用于 Microsoft Visual C++。 不正确。 Clear 将对从流返回的字符串进行操作,而不是流本身。以上是关于如何清除字符串流变量?的主要内容,如果未能解决你的问题,请参考以下文章