c++流提取操作符重载
C++ stream extraction operator overloading
这是一个关于用户编写的c++输入流提取操作符(>>)的哲学(规范设计)的问题。
假设在进入>>操作符实现时(对于用户编写的类),已经为输入流设置了eof标志。
用户编写的提取操作符(>>)
- 设置失败标志(因为找不到所需对象的实例)
- 返回到调用者,eof标志仍然设置。
如果使用第二种方法,则意味着调用者在尝试调用>>操作符之前必须始终检查eof标志。原因是>>操作符可能成功地提取所需类的实例并设置eof标志。
原始代码如下。根据下面的注释,这段代码似乎是错误的。如果eof在输入时已经设置,提取操作符返回时eof仍然设置。如果设置了eof,但没有设置bad和fail,那么应该提取字符串来设置失败位。当然,可以直接设置失效位。
/* Implement the C/C++ >> (stream input) operator as a non-member
function */
std::istream &operator>>(std::istream& is, DecNumber &val) {
DecContext context{DecContext::defInit};
uint32_t status;
/* The true value below prevents whitespace from being skipped */
std::istream::sentry s(is, true);
std::string inStr;
/* Check if the input stream is in a good state. Just return to the
caller if the input stremm is not in a good state. The caller
must handle this condition. */
if(!s)
return is;
/* Get a string from the input stream. This string is converted to
a DecNumber below. Just return to the caller if this step causes
any stream related errors. Note that reaching the end of the
input is not a stream related error here. A decimal number might
be the absolute last thing in the stream. */
is >> inStr;
if (is.bad() || is.fail())
return is;
/* Try to convert the string to a DecNumber using the default context
value */
decNumberFromString(val.getDecVal(), inStr.c_str(), context.getDecCont());
status = context.DecContextGetStatus();
/* Remove a few status bits we don't care about */
status &= ~(DEC_Inexact + DEC_Rounded);
if (status)
is.setstate(std::ios_base::failbit);
return is;
}
您应该执行解决方案1。
当你有疑问的时候,看看已经做了什么。如下图所示,如果我们试图从EOF状态的流中读取数据,就会设置失败位。
注意EOF并不是唯一的失败方式。尝试在下面的代码中设置std::string vals = "52 43 A";
。
operator>>
实际上没有流值,则应设置 failbit
。EOF只是其中一个原因。
#include <sstream>
#include <iostream>
#include <string>
void print_stream (std::istream & print_me, int const & i)
{
std::cout << "i: " << i << "n";
std::ios_base::iostate bits = print_me.rdstate();
std::cout << "good: " << (bits & std::ios_base::goodbit) <<
", bad: " << (bits & std::ios_base::badbit) <<
", fail: " << (bits & std::ios_base::failbit) <<
", eof: " << (bits & std::ios_base::eofbit) << "n";
std::cout << "n----------------------------nn";
}
int main (void)
{
std::string vals = "52 43";
std::istringstream iss(vals);
int i;
iss >> i;
print_stream (iss, i);
iss >> i;
print_stream (iss, i);
iss >> i;
print_stream (iss, i);
iss >> i;
print_stream (iss, i);
return 0;
}
输出$ ./a.exe
i: 52
good: 0, bad: 0, fail: 0, eof: 0
----------------------------
i: 43
good: 0, bad: 0, fail: 0, eof: 2
----------------------------
i: 43
good: 0, bad: 0, fail: 4, eof: 2
----------------------------
i: 43
good: 0, bad: 0, fail: 4, eof: 2
----------------------------
注意,典型的读模式循环是…
while (input >> var >> var2 >> var3)
{
// failbit is not set. All reads succeeded.
// Do Stuff
}
如果您需要检测在读取多个值时是否发生故障,那么您需要更复杂一些,并做一些测试,如…
while (true)
{
if (input >> var)
{
// We successfully read first value
if (input >> var2 >> var3)
{
// We succesfully read all the values!
// Do stuff
}
else
{
ErrorLog ("Partial line read!");
break;
}
else
{
// Nothing else to read
break;
}
}
"如果使用第二种方法,则意味着调用者在尝试调用>>操作符之前必须始终检查eof标志。"
不,为什么你认为他们需要这样做?
"用户编写的提取操作符(>>)是否应该设置失败标志(因为没有找到所需对象的实例),或者它是否应该返回到仍然设置了eof标志的调用者。"
后一个选项,当然,你不应该在重载提取操作符中管理流状态,除非你添加了自己的验证规则(例如,期待std::string
字段的特定字符模式)。重载操作符使用的子提取操作通常可以正确地完成。
假设你有如下内容:
struct MyType {
std::string field1;
int field2;
double field3;
}
std::istream& operator>>(std::istream& is, MyType& myinstance) {
is >> field1;
is >> field2;
is >> field3;
return is;
}
每个提取将设置字段为其默认构造值,以防operator>>()
失败,因为流处于eof()
状态,并且值将保留在试图提取的字段的原始状态。
我实际上不认为有必要对eof()
进行任何额外的检查,或者在您的重载输入操作符中将流设置为fail()
状态。
客户端(调用者)将简单地使用如下内容:
std::ifstream input("MyFile.txt");
std::vector<MyType> allObjects;
MyType curObject;
while(input >> curObject) {
allObjects.push_back(curObject);
}
你看,没有必要在任何地方检查input.eof()
- 重载操作符+:表达式必须是整型或无作用域枚举类型
- 重载操作符
- 如何重载操作符==外模板类使用友元函数
- 重载*操作符,使其在左右两边都工作
- 重载操作符<对于非随机迭代器
- 在c++中重载操作符的时间和原因
- 如何在c++中重载=操作符来通过引用进行复制
- 如何在c++中获取定义为友元的重载操作符的地址
- 使用重载操作符的文件操作表达式没有给出预期的结果
- 重载操作符()
- 重载操作符()并在类内使用
- 类中的重载操作符+
- 定时使用重载操作符
- c++带类的重载操作符
- 用列表容器重载[]操作符
- 重载操作符=
- 任何重载操作符()的静态检测
- 重载操作符以处理类对象
- 在使用另一个类的类中重载操作符==
- 派生类和基类中的重载操作符不同