I would like to be able to catch different logic_errors and be able to differentiate them. Can I somehow pass additional parameters to the logical error which to catch later. The idea is that I need to print. Right now I am just catching the default errors that stof can return.
"Sorry invalid temperature" or "Sorry invalid rainfall"
P.S. The function stringToTime converts dates to strings and throws logic error with some text, if the date doesn't match certain criteria. Thank you!
try{
tm date = stringToTime(year);
float temp = stof(temperature);
float rain = stof(rainfall);
}
catch(logic_error e){
if( string(e.what()) == "stof"){
cout << "Sorry wrong arguments for either Temperature or Rainfall" << endl;
}else{
cout << e.what() << endl;
}
}
what() text is implementation defined, and GCC only does lazy (but efficient) printing like that. But you can split the extraction into two functions:
float getTemperature(const std::string& temperature) {
try{
return std::stof(temperature);
}
catch(std::logic_error& e){
std::cout << "Sorry wrong argument for Temperature" << std::endl;
throw e; //or you can throw a different exception
}
}
//same for getRainfall()
void validateArguments()
{
try {
tm date = stringToTime(year);
float temp = getTemperature(temperature);
float rain = getRainfall(rainfall);
} catch (std::logic_error& e) {
if( string(e.what()) == "stof"){
//no need to print anymore, but you can e.g. ask for arguments again or something
}else{
cout << e.what() << endl;
}
}
Side note: Consider using your own exception class for throwing from stringToTime (it can be derived from std::logic_error if you prefer, or straight from std::exception). It's safer and compiler-independent way to distinguish different exceptions. Leave exceptions from standard library to standard library.
Pass in parameters as part of the logic_error constructor. As below in the HERE! comment.
/******************************************************************************
Welcome to GDB Online.
GDB online is an online compiler and debugger tool for C, C++, Python, PHP, Ruby,
C#, VB, Perl, Swift, Prolog, Javascript, Pascal, HTML, CSS, JS
Code, Compile, Run and Debug online from anywhere in world.
*******************************************************************************/
// From: https://stackoverflow.com/questions/61941722/differentiate-logic-error-in-c
#include <stdio.h>
#include <string>
#include <iostream>
using namespace std;
tm stringToTime( string input )
{
tm retval;
retval.tm_year = stof( input ) - 1990;
logic_error e( "stof" ); // HERE! Is the constructor that can differentiate the logic_error->when() value.
throw( e );
return retval;
}
int main()
{
printf("User defined logic_error example.\n");
string year = "2020";
string temperature = "70";
string rainfall = "1";
int lineNum = 10;
string fieldNames[2] = { "temperature", "rainfaill" };
try{
tm date = stringToTime(year);
float temp = stof(temperature);
float rain = stof(rainfall);
}
catch(logic_error e){
if( string( e.what() ) == "stof"){
cout << "Sorry wrong arguments for either Temperature or Rainfall" << endl;
}else{
cout << e.what() << " on line " << lineNum + 1 << " type " << fieldNames[0] << endl;
}
}
return 0;
}
Related
I'm trying to parse a string to detect if it is a number or if it is a name, etc.
And to do it I'm putting examples like "10 ms": it parses the 10 only, without returning an error.
What I want to do is to get if the whole string can be parsed or not, not only a part of it.
Here is my code:
string s = "10 ms";
bool number = true;
try {
stof(s, nullptr);
} catch (invalid_argument){
number = false;
}
It returns that is a number. And the returned number from stof is 10.
I have also tried using catch(...), same problem.
Looking at the documentation of std::stof, it has 2 arguments, of which one is an output argument.
This can be used the following way:
#include <string>
#include <iostream>
int main(int, char**)
{
try
{
std::string s = "10 ms";
bool number = true;
std::size_t nofProcessedChar = 0;
auto nr = std::stof(s, &nofProcessedChar);
std::cout << "found " << nr << " with processed " << nofProcessedChar << std::endl;
auto allCharsProcessed = nofProcessedChar == s.size();
std::cout << "all processed: " << allCharsProcessed << std::endl;
}
catch(const std::invalid_argument &)
{
std::cout << "Invalid argument " << std::endl;
}
catch (const std::out_of_range &)
{
std::cout << "Out of range" << std::endl;
}
}
Code at compiler explorer
As you can see in the output
found 10 with processed 2
all processed: 0
It prints 0 for all processed, which is the numeric casting value of bool.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
I would like to start this thread by thanking you for taking to the time to read my query.
I have created a function called retreiveFile which as you would expects retreives a file and reads from it. The text it reads is a set of numbers and text which represent names, cost and that sort of thing.
I have used istringstream to read through the file, determine the starting number(so I know what the line represents(property, card, ect)). Currently I have the file outputting the text but only with its corresponding data.
Example:
9 Oakmoor Road 80 5 0
9 Eldon Road 50 5 0
I need to know how I could pass this information into a class as I assume because I am going to have many objects of the same class I need to pass the data into main somehow.
(I tried creating the class using constructor within the function but it would not work)
I am assuming I would have to create pointers for the information, pass it to main, create the constructors and then delete the pointers.
My question to you would be how could I do this efficiently as I need to create around 30 objects which could fit in several different types of classes as some have different parameters.
I'm sorry in advance in some information seems vague or confusing I am still, in my head, trying to picture how I could do it.
An example of one of the ways I've separated the text within the file so I can easily pass it over to its correct class.
if (word[i].find("1") == 0){ //starts with 1
istringstream is(word[i]);
string aword;
int loopTimes = 0;
while (is >> aword) { // read each word from line
string propertyArray[6];
if (loopTimes == 0){
string stringIdentificationNum = aword;
/* const char * charIdentificationNum = stringIdentificationNum.c_str();
int identificationNum = atoi(charIdentificationNum); */
cout << "(1.1)" << aword;
propertyArray[0] = aword;
}
else if (loopTimes == 1){
cout << "(1.2)" << aword;
propertyArray[1] = aword;
}
else if (loopTimes == 2){
cout << "(1.3)" << aword;
propertyArray[2] = aword;
}
else if (loopTimes == 3){
cout << "(1.4)" << aword;
propertyArray[3] = aword;
}
else if (loopTimes == 4){
cout << "(1.5)" << aword;
propertyArray[4] = aword;
}
else if (loopTimes == 5){
cout << "(1.6)" << aword << endl;
propertyArray[5] = aword;
}
loopTimes++;
/* Property(propertyArray[0], propertyArray[1], propertyArray[2], propertyArray[3], propertyArray[4], propertyArray[5]); */
}
}
An example of the propertyClass
class Property : public Card{
private:
int identificationNum;
string propertyName;
int propertyCost;
int propertyRent;
int propertyColour;
public:
//constructor
Property::Property(int inputIdentificationNum, string inputFName, string inputSName, int inputCost, int inputPropertyRent, int inputPropertyColour){
setIdentificationNum(inputIdentificationNum);
setFirstName(inputFName, inputSName);
setPropertyCost(inputCost);
setPropertyRent(inputPropertyRent);
setPropertyColour(inputPropertyColour);
cout << "Property Created" << endl;
}
//set data
void setIdentificationNum(int inputIdentificationNum){
identificationNum = inputIdentificationNum;
}
void setFirstName(string inputFName, string inputSName){
string nameCombined = inputFName + " " + inputSName;
propertyName = nameCombined;
}
void setPropertyCost(int inputCost){
propertyCost = inputCost;
}
void setPropertyRent(int inputPropertyRent){
propertyRent = inputPropertyRent;
}
void setPropertyColour(int inputPropertyColour){
propertyColour = inputPropertyColour;
}
//retreive data
int getIdentificationNum() {
return identificationNum;
}
string getName(){
return propertyName;
}
int getPropertyCost(){
return propertyCost;
}
int getPropertyRent(){
return propertyRent;
}
int getPropertyColour(){
return propertyColour;
}
};
Thank you in advance for reading this thread.
Passing pointers around is unnecessary for this task and is actually frowned on. An objects data should stay locked up and hidden in the object unless you have a really good reason to expose it. In this case OP doesn't.
What follows cleans up OP's code and fixes some of the problems that made their attempt unworkable and probably lead them down the road to over-complicating things further.
Example is a container for a list of properties. Rather than passing around pointers to to the properties, OP can pass around references to Example and read the properties from example. This allows Example to defend itself from its clients. With a pointer to a property, a client could mistakenly change change a value that could result in breaking Example or another client of Example. With a Getter method, Example can control access to the properties with whatever grain is required.
Example, in this case, allows everyone to see properties, so long as the property exists, but does not allow changing the property.
#include <iostream>
#include <string>
#include <sstream>
#include <stdexcept>
class Example
{
private:
static constexpr size_t MAX_PROPERTIES = 6;
std::string propertyArray[MAX_PROPERTIES];
propertyArray is now a member variable and has scope that matches the object. Consider using a vector. It is not arbitrarily limited in size
public:
Example(std::stringstream & is)
{
std::string aword;
size_t looptimes = 0;
while (is >> aword && looptimes < MAX_PROPERTIES)
{
std::cout << "(1." << looptimes + 1 << ")" << aword << std::endl;
propertyArray[looptimes] = aword;
looptimes++;
This is where making propertyArray a vector really helps. You can use the push_back method to keep adding more and more properties. If you have a case with 8 properties in the future, it uses the exact same code as the 8 property version and you don't have to guard against overflow with the && looptimes < 6 in the while
}
}
std::string getProperty(size_t propertyNo)
New method used to get the properties for clients of Example. That way you don't have to pass around pointers to Example's data. Just pass around Example and if Example wants to give data, it can. No one can use an unprotected back door into Example to screw with Example's data without permission.
{
if (propertyNo < MAX_PROPERTIES)
{
return propertyArray[propertyNo];
}
throw std::out_of_range("Invalid property number");
}
};
And to test it out...
int main()
{
std::stringstream is ("A B C D E F G");
Example test(is);
try
{
std::cout << test.getProperty(4) << std::endl;
std::cout << test.getProperty(6) << std::endl;
}
catch (std::out_of_range & exc)
{
std::cout << exc.what() << std::endl;
}
}
Output:
(1.1)A
(1.2)B
(1.3)C
(1.4)D
(1.5)E
(1.6)F
E
Invalid property number
And now with a std::vector:
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <vector>
class Example
{
private:
std::vector<std::string> propertyArray;
public:
Example(std::stringstream & is)
{
std::string aword;
while (is >> aword)
{
propertyArray.push_back(aword);
std::cout << "(1." << propertyArray.size() << ")" << aword << std::endl;
}
}
std::string getProperty(size_t propertyNo)
{
if (propertyNo < propertyArray.size())
{
return propertyArray[propertyNo];
}
throw std::out_of_range("Invalid property number");
}
};
int main()
{
std::stringstream is ("A B C D E F G");
Example test(is);
try
{
std::cout << test.getProperty(4) << std::endl;
std::cout << test.getProperty(7) << std::endl;
}
catch (std::out_of_range & exc)
{
std::cout << exc.what() << std::endl;
}
}
Output:
(1.1)A
(1.2)B
(1.3)C
(1.4)D
(1.5)E
(1.6)F
(1.7)G
E
Invalid property number
This is the code i am using
string exptype(string s)
{
string type = "";
try
{
if (regex_match(s.c_str(), regex("101(0|1)*111")))
type = "a valid binary";
else if (regex_match(s.c_str(), regex("[a-zA-Z]")))
type = "a valid combination of alphanum letters";
else if (regex_match(s.c_str(), regex("\([0-9]{3}\)[0-9]{3}-{0-9}{4}")))
type = "a valid phone number";
else if (regex_match(s.c_str(), regex("(19|20)[0-9][0-9]-(0[1-9]|1[0-2])- ((0[1-9])|([1-2][0-9])|(3[0-1]))")))
type = "a valid date";
else
type = "an invalid string";
}
catch (std::regex_error& e)
{
cout << e.code() << endl;
}
return type;
}
Then my main is the following:
int main()
{
string input;
do
{
cout << "Enter the string that will be validated.." << endl;
getline(cin, input);
if (input != "q")
{
cout << "This is " << exptype(input) << endl;
}
else
break;
} while (true);
return 0;
}
The mentioned code will sometimes work and sometimes it will throw an exception with the error code: 7
I have googled it and found that the error is error_brace: The expression contained mismatched braces ({ and }).
I dont see what is wrong here, any help is appreciated.
Thanks
As Mariano pointed out, you should replace {0-9} with [0-9]. You also better use raw string litterals when dealing with regular expressions or other string with escaping \. For example:
regex_match(s.c_str(), regex(R"reg(\([0-9]{3}\)[0-9]{3}-[0-9]{4})reg"))
I'm just learning how to use exceptions in C++ and have come across weird behavior in my "test" code. (excuse overly stupid questions like this one, please...it's NOT lack of research/effort, just lack of experience!) If I'm catching just the exception DivideByZero it works fine.
But introducing the second exception StupidQuestion makes the code not work exactly how I expected. How I wrote it below I thought it should take care of the DivideByZero exception if it needs to, and if not then check if StupidQuestion occurs, and if not just go back to the try clause and print the normal result. But if I input, say, a=3 and b=1, the program redirects to the DivideByZero try clause instead of the StupidQuestion one. The weird thing is, though, divide does seem to be throwing StupidQuestion (see via cout statement), but it's not catching right, as also seen by the absense of the cout statement.
#include <iostream>
#include <cstdlib>
using namespace std;
const int DivideByZero = 42;
const int StupidQuestion=1337;
float divide (int,int);
main(){
int a,b;
float c;
cout << "Enter numerator: ";
cin >> a;
cout << "Enter denominator: ";
cin >> b;
try{
c = divide(a,b);
cout << "The answer is " << c << endl;
}
catch(int DivideByZero){
cout << "ERROR: Divide by zero!" << endl;
}
catch(int StupidQuestion){
cout << "But doesn't come over here...?" << endl;
cout << "ERROR: You are an idiot for asking a stupid question like that!" << endl;
}
system("PAUSE");
}
float divide(int a, int b){
if(b==0){
throw DivideByZero;
}
else if(b==1){
cout << "It goes correctly here...?" << endl;
throw StupidQuestion;
}
else return (float)a/b;
}
I was wondering if it had something to do with the fact that DivideByZero and StupidQuestion were both of type int, so I changed the code to make StupidQuestion be of type char instead of int. (So: const char StupidQuestion='F'; and catch(char StupidQuestion) were really the only things changed from above) And it worked fine.
Why isn't the above code working when the two exceptions have the same type (int)?
Instead of this
catch(int DivideByZero) {
cout << "ERROR: Divide by zero!" << endl;
}
catch(int StupidQuestion) {
cout << "But doesn't come over here...?" << endl;
cout << "ERROR: You are an idiot for asking a stupid question like that!" << endl;
}
you are looking for
catch (int errval) {
if (errval == DivideByZero) {
cout << "ERROR: Divide by zero!" << endl;
}
else if (errval == StupidQuestion) {
cout << "ERROR: You are an idiot for asking a stupid question like that!" << endl;
}
else {
throw; // for other errors, keep searching for a handler
}
}
The variable name inside the catch clause is creating a new local variable, which has no relation to a global constant with the same name.
Also note that there will be no way to catch just one error number... but you can rethrow unknown errors as I show.
catch(int DivideByZero) { }
catch(int StupidQuestion) { }
Both catch blocks catch ints, they're just named differently. Only the first one can ever be entered, the second one is dead code.
When choosing a handler for an exception only type is taken into account, and neither values nor addresses (addresses of variables are not applicable here at all because of how exceptions work), also names of variables do not exist after compilation.
The first appropriate handler for the exception is always chosen.
Please look my answer to another question for details: https://stackoverflow.com/a/45436594/1790694
So I have an upcoming assignment dealing with exceptions and using them in my current address book program that most of the homework is centered around. I decided to play around with exceptions and the whole try catch thing, and using a class design, which is what I will eventually have to do for my assignment in a couple of weeks. I have working code that check the exception just fine, but what I want to know, is if there is a way to standardize my error message function, (i.e my what() call):
Here s my code:
#include <iostream>
#include <exception>
using namespace std;
class testException: public exception
{
public:
virtual const char* what() const throw() // my call to the std exception class function (doesn't nessasarily have to be virtual).
{
return "You can't divide by zero! Error code number 0, restarting the calculator..."; // my error message
}
void noZero();
}myex; //<-this is just a lazy way to create an object
int main()
{
void noZero();
int a, b;
cout << endl;
cout << "Enter a number to be divided " << endl;
cout << endl;
cin >> a;
cout << endl;
cout << "You entered " << a << " , Now give me a number to divide by " << endl;
cin >> b;
try
{
myex.noZero(b); // trys my exception from my class to see if there is an issue
}
catch(testException &te) // if the error is true, then this calls up the eror message and restarts the progrm from the start.
{
cout << te.what() << endl;
return main();
}
cout <<endl;
cout << "The two numbers divided are " << (a / b) << endl; // if no errors are found, then the calculation is performed and the program exits.
return 0;
}
void testException::noZero(int &b) //my function that tests what I want to check
{
if(b == 0 ) throw myex; // only need to see if the problem exists, if it does, I throw my exception object, if it doesn't I just move onto the regular code.
}
What I would like to be able to do is make it so my what() function can return a value dependent on what type of error is being called on. So for instance, if I were calling up an error that looked a the top number,(a), to see if it was a zero, and if it was, it would then set the message to say that "you can't have a numerator of zero", but still be inside the what() function. Here's an example:
virtual const char* what() const throw()
if(myex == 1)
{
return "You can't have a 0 for the numerator! Error code # 1 "
}
else
return "You can't divide by zero! Error code number 0, restarting the calculator..."; // my error message
}
This obviously wouldn't work, but is there a way to make it so I'm not writing a different function for each error message?
Your code contains a lot of misconceptions. The short answer is yes, you can change what() in order to return whatever you want. But let's go step by step.
#include <iostream>
#include <exception>
#include <stdexcept>
#include <sstream>
using namespace std;
class DivideByZeroException: public runtime_error {
public:
DivideByZeroException(int x, int y)
: runtime_error( "division by zero" ), numerator( x ), denominator( y )
{}
virtual const char* what() const throw()
{
cnvt.str( "" );
cnvt << runtime_error::what() << ": " << getNumerator()
<< " / " << getDenominator();
return cnvt.str().c_str();
}
int getNumerator() const
{ return numerator; }
int getDenominator() const
{ return denominator; }
template<typename T>
static T divide(const T& n1, const T& n2)
{
if ( n2 == T( 0 ) ) {
throw DivideByZeroException( n1, n2 );
}
return ( n1 / n2 );
}
private:
int numerator;
int denominator;
static ostringstream cnvt;
};
ostringstream DivideByZeroException::cnvt;
In the first place, runtime_error, derived from exception, is the adviced exception class to derive from. This is declared in the stdexcept header. You only have to initialize its constructor with the message you are going to return in the what() method.
Secondly, you should appropriately name your classes. I understand this is just a test, but a descriptive name will always help to read and understand your code.
As you can see, I've changed the constructor in order to accept the numbers to divide that provoked the exception. You did the test in the exception... well, I've respected this, but as a static function which can be invoked from the outside.
And finally, the what() method. Since we are dividing two numbers, it would be nice to show that two numbers that provoked the exception. The only way to achieve that is the use of ostringstream. Here we make it static so there is no problem of returning a pointer to a stack object (i.e., having cnvt a local variable would introduce undefined behaviour).
The rest of the program is more or less as you listed it in your question:
int main()
{
int a, b, result;
cout << endl;
cout << "Enter a number to be divided " << endl;
cout << endl;
cin >> a;
cout << endl;
cout << "You entered " << a << " , Now give me a number to divide by " << endl;
cin >> b;
try
{
result = DivideByZeroException::divide( a, b );
cout << "\nThe two numbers divided are " << result << endl;
}
catch(const DivideByZeroException &e)
{
cout << e.what() << endl;
}
return 0;
}
As you can see, I've removed your return main() instruction. It does not make sense, since you cannot call main() recursively. Also, the objective of that is a mistake: you'd expect to retry the operation that provoked the exception, but this is not possible, since exceptions are not reentrant. You can, however, change the source code a little bit, to achieve the same effect:
int main()
{
int a, b, result;
bool error;
do {
error = false;
cout << endl;
cout << "Enter a number to be divided " << endl;
cout << endl;
cin >> a;
cout << endl;
cout << "You entered " << a << " , Now give me a number to divide by " << endl;
cin >> b;
try
{
result = DivideByZeroException::divide( a, b ); // trys my exception from my class to see if there is an issue
cout << "\nThe two numbers divided are " << result << endl;
}
catch(const DivideByZeroException &e) // if the error is true, then this calls up the eror message and restarts the progrm from the start.
{
cout << e.what() << endl;
error = true;
}
} while( error );
return 0;
}
As you can see, in case of an error the execution follows until a "proper" division is entered.
Hope this helps.
You can create your own exception class for length error like this
class MyException : public std::length_error{
public:
MyException(const int &n):std::length_error(to_string(n)){}
};
class zeroNumerator: public std::exception
{
const char* what() const throw() { return "Numerator can't be 0.\n"; }
};
//...
try
{
myex.noZero(b); // trys my exception from my class to see if there is an issue
if(myex==1)
{
throw zeroNumerator(); // This would be a class that you create saying that you can't have 0 on the numerator
}
}
catch(testException &te)
{
cout << te.what() << endl;
return main();
}
You should always use std::exception&e. so do
catch(std::exception & e)
{
cout<<e.what();
}
You should consider a hierarchy of classes.
The reason for it might not be obvious when trying to use exceptions just for transferring a string, but actual intent of using exceptions should be a mechanism for advanced handling of exceptional situations. A lot of things are being done under the hood of C++ runtime environment while call stack is unwound when traveling from 'throw' to corresponded 'catch'.
An example of the classes could be:
class CalculationError : public std::runtime_error {
public:
CalculationError(const char * message)
:runtime_error(message)
{
}
};
class ZeroDeviderError : public CalculationError {
public:
ZeroDeviderError(int numerator, const char * message)
: CalculationError(message)
, numerator (numerator)
{
}
int GetNumerator() const { return numerator; }
private:
const int numerator;
};
Providing different classes for the errors, you give developers a chance to handle different errors in particular ways (not just display an error message)
Providing a base class for the types of error, allows developers to be more flexible - be as specific as they need.
In some cases, they might want to be specific
} catch (const ZeroDividerError & ex) {
// ...
}
in others, not
} catch (const CalculationError & ex) {
// ...
}
Some additional details:
You should not create objects of your exceptions before throwing in the manner you did. Regardless your intention, it is just useless - anyway, you are working with a copy of the object in the catch section (don't be confused by access via reference - another instance of the exception object is created when throwing)
Using a const reference would be a good style catch (const testException &te) unless you really need a non-constant object.
Also, please note that the type (classes) used for exceptions are not permitted to throw exceptions out of their copy constructors since, if the initial exception is attempted to be caught by value, a call of copy constructor is possible (in case is not elided by the compiler) and this additional exception will interrupt the initial exception handling before the initial exception is caught, which causes calling std::terminate.
Since C++11 compilers are permitted to eliminate the copying in some cases when catching, but both the elision is not always sensible and, if sensible, it is only permission but not obligation (see https://en.cppreference.com/w/cpp/language/copy_elision for details; before C++11 the standards of the language didn’t regulate the matter).
Also, you should avoid exceptions (will call them the additional) to be thrown out of constructors and move constructors of your types (classes) used for exceptions (will call them initial) since the constructors and move constructors could be called when throwing objects of the types as initial exceptions, then throwing out an additional exception would prevent creation of an initial exception object, and the initial would just be lost. As well as an additional exception from a copy constructor, when throwing an initial one, would cause the same.