有效获取字符串流的子流
我需要实现一种机制,可以使用文本源初始化自定义类的向量,其中源的每一行代表我的类的一个实例。为了实现这一目标,我为我的类和 stringstream
实现了 operator >>
。当我阅读源代码时,我会逐行获取原始源代码的子流,然后每次解析该子流。这对我来说有三个好处。首先,这样我可以确保文本源的一行恰好代表我的类的一个实例。其次,由于解析后的行的其余部分被忽略,我可以安全地在文本源的任何行中添加任何注释,这肯定会被解析器忽略。第三,我不需要提及原始源中向量的长度,因为我第一次遇到解析错误(我检查了 fail
和 bad
流的位来确认这一点)我知道向量声明已经结束。
为了逐行解析,我使用以下代码:
std::stringstream fullStream;
std::stringstream lineStream;
std::string str;
bool isValid;
myClass newInstance;
std::vector < myClass > result;
// Fill fullStream from external source (codepart omitted)
isValid = true;
while ( isValid && ! fullStream.eof ( ) ) {
std::getline ( fullStream, str );
lineStream.clear ( );
lineStream.str ( str );
lineStream >> newInstance;
isValid = ! lineStream.fail ( );
if ( isValid ) {
result.push_back ( newInstance );
}
}
虽然此代码工作正常,但我想知道是否有更好的方法来实现相同的结果。特别是,如果有更有效的方法将行从 fullStream
提取到 lineStream
。
谢谢,
阿达姆
I need to implement a mechanism where I can initialize a vector of my custom class using a text source, where each line of the source is representing one instance of my class. To achieve this, I implemented the operator >>
for my class and stringstream
. When I read the source, I go line-by-line and get a substream of my original source, then parse the substream each time. This has three benefits for me. First, this way I can make sure that one line of the text source would represent exactly one instance of my class. Second, as the rest of the line after parsing is ignored, I can safely add any comment in any line of my text source, which would surely get ignored by the parser. And third, I don't need to mention the length of the vector in my original source, since the first time I get a parsing error (I check the fail
and bad
bits of the stream to confirm this) I know that the vector declaration is over.
To parse line-by-line, I'm using the following code:
std::stringstream fullStream;
std::stringstream lineStream;
std::string str;
bool isValid;
myClass newInstance;
std::vector < myClass > result;
// Fill fullStream from external source (codepart omitted)
isValid = true;
while ( isValid && ! fullStream.eof ( ) ) {
std::getline ( fullStream, str );
lineStream.clear ( );
lineStream.str ( str );
lineStream >> newInstance;
isValid = ! lineStream.fail ( );
if ( isValid ) {
result.push_back ( newInstance );
}
}
Although this code works fine, I'm wondering if there was a better way to achieve the same result. Specially, if there was a more efficient way to extract a line from fullStream
to lineStream
.
Thanks,
Ádám
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
首先,如果代码有效,那实际上只是偶然。惯用语
处理这个问题的方法是:
在读取之前检查
eof()
很少有用,并且不检查使用
getline
之前的结果几乎肯定是一个错误。尝试重用
stringstream
比只需创建一个新的;有各种各样的状态,可能或可能
不必重置。流有一种记忆错误的机制
状态,所以你可能想使用它。 (如果您想继续使用
fullStream
进行其他事情后出错,问题就多了复杂,因为你已经提取了失败的行,并且你
不能把它放回去。)如果你只是在阅读,你应该使用
std::istringstream
,而不是std::stringstream
(它有很多额外行李);一般来说,使用双向的情况非常非常罕见
溪流。
First, if the code works, it is really only by chance. The idiomatic
way of handling this is:
Checking
eof()
before a read is rarely useful, and not checking theresults of your
getline
before using it is almost certainly an error.Trying to reuse a
stringstream
is more complex and error prone thansimply creating a new one; there is all sorts of state which may or may
not have to be reset. Streams have a mechanism for memorizing error
state, so you probably want to use this. (If you want to continue using
fullStream
for other things after the error, the problem is morecomplex, because you've already extracted the line which failed, and you
can't put it back.) And if you're only reading, you should use
std::istringstream
, and notstd::stringstream
(which has a lot ofextra baggage); in general, it's very, very rare to use a bi-directional
stream.
一个明显的替代方案是让您的
operator>>
自行逐行读取,这样您就不必在外部执行此操作:这样,从文件读取数据的代码就变成了更简单一点:
编辑:如果您不想将面向行的读取直接构建到
MyClass
的operator>>
中,另一种可能性是使用代理类:然后当你想做的时候面向行的读取,您读取代理类的对象,但存储原始类的对象:
但是,当/如果您想读取对象流而不是对象行,您可以直接使用对象自己的
operator>>
:One obvious alternative would be to have your
operator>>
do line-by-line reading itself, so you don't have to do that externally:With that, code to read data from a file becomes a little more straightforward:
Edit: if you don't want to build the line-oriented reading directly into the
operator>>
forMyClass
, another possibility is to use a proxy class:Then when you want to do line-oriented reading, you read objects of the proxy class, but store objects of the original class:
But, when/if you want to read a stream of objects instead of lines of objects, you use the object's own
operator>>
directly: