Reputation: 53
I am reading Jesse Liberty's SAMS Teach Yourself C++ in 10 Minutes and testing the examples in the book. I find that there are some bugs in the code about file i/o but I don't know where they are. The book does not mention anything about them. I think the problem is caused by fstream
and catch(...)
but I don't know how to fix it. So I would like to seek help from experienced C++ users here to help me.
I don't know why the program always call ErrorHandling::handleNotANumberError();
when the input file is empty.
Moreover, the program has more errors when the input file does not exist. Exceptions are caught and basic_ios::clear
is read. Why are there errors?
When I delete the codes about exceptions, it can work well when the file does not exist.
And when I input from an empty file, the message "invalid operator" is present.
I think that invalid operator is the eof character. Is it?
I have searched in Google but still cannot figure out what is happening. I know the following code is a bit long but I really want to know what happens.
ifstream tapeInputStream; //global variable for callback
char getOperator()
{
char operatorInput;
if
(
tapeInputStream.is_open() &&
( !tapeInputStream.eof() )
)
{
tapeInputStream >> operatorInput;
}
else
{
cin >> operatorInput;
}
return operatorInput;
}
float getOperand()
{
float operandInput = 1;
if
(
tapeInputStream.is_open() &&
( !tapeInputStream.eof() )
)
{
tapeInputStream >> operandInput;
}
else
{
cin >> operandInput;
}
return operandInput;
}
void showResult( float theResult )
{
cout << endl << "Result: " << theResult << endl;
}
int main( int argc, char* argv[] )
{
if ( argc > 1 ) //a filename is present
{
try
{
tapeInputStream.exceptions( tapeInputStream.failbit ); //cin or ofstream?
tapeInputStream.open( argv[1], ios_base::in );
}
catch ( ios_base::failure &ioError )
{
ErrorHandling::handleInputStreamError( tapeInputStream, ioError );
//the stream will be unopened but the failbit will not be set
}
}
Calculator::aCalculatorExternalInterface CalculatorExternalInterface;
CalculatorExternalInterface.getAnOperator = getOperator;
CalculatorExternalInterface.getAnOperand = getOperand;
CalculatorExternalInterface.showResult = showResult;
int result = Calculator::calculateFromInput( CalculatorExternalInterface );
tapeInputStream.close(); //close the file to make output stream in tape() possible
Calculator::tape( '.', 0, argv[1] ); //stream and delete the tape
return result;
}
bool nextCalculation
(
const aCalculatorExternalInterface &theCalculatorExternalInterface
)
{
char operatorInput = theCalculatorExternalInterface.getAnOperator();
switch ( operatorInput )
{
case '.': //stop
return true; //done will become true
case '?': //show the tape
tape( operatorInput );
return false;
case '=': case '@': //no operand sent to accumulator
{
anOperator operatorValue =
( operatorInput == '=' ? query : reset );
float result = accumulator( operatorValue );
if ( operatorValue == query )
{
theCalculatorExternalInterface.showResult( result );
}
return false;
} //use curly brackets to define the scope
case '+': case '-': case '*': case '/': //calculation
{
float number = theCalculatorExternalInterface.getAnOperand();
anOperator operatorValue =
operatorInput == '+' ? add :
operatorInput == '-' ? subtract :
operatorInput == '*' ? multiply :
divide;
accumulator( operatorValue, number );
tape( operatorInput, number );
return false;
}
case '!': //self-test
selfTest();
return false;
default: //anythings else is an error
throw runtime_error( "Error: Invalid operator.");
}
}
int calculateFromInput
(
aCalculatorExternalInterface &theCalculatorExternalInterface
)
{
ErrorHandling::initialise();
bool done = false;
do
{
try
{
done = nextCalculation( theCalculatorExternalInterface );
}
catch ( runtime_error runtimeError )
{
ErrorHandling::handleRuntimeError( runtimeError );
}
catch (...)
{
ErrorHandling::handleNotANumberError();
}
}
while ( !done ); //continue when undone
return 0;
}
Upvotes: 0
Views: 1009
Reputation: 53
I have no idea what the exceptions thrown are so I just add some if statements to prevent any errors due to an empty file or non-existing file. It may be better to handle the sources of problems before they causes problems.(I really don't know much about exceptions.)
Here are my new codes in main.cpp
if ( argc > 1 ) //a filename is present
{
try
{
tapeInputStream.exceptions( tapeInputStream.failbit );
if ( existFile( argv[1] ) ) //no need to read file if it does not exist
{
tapeInputStream.open( argv[1], ios_base::in );
if ( emptyFile() ) //no need to read file if it is empty
{
tapeInputStream.close();
}
}
}
catch ( ios_base::failure &ioError )
{
ErrorHandling::handleInputStreamError( tapeInputStream, ioError );
}
}
Upvotes: 1
Reputation: 2329
In line catch ( ios_base::failure &ioError )
you are just handling one type of error. try catch(...)
for all the errors. Please mention what are the other error gives after running the code.
Also please be sure that you are providing the argument in proper way.
Executable<space>file_name_as_argument.
Upvotes: 0