Stop process if there is an error in the constructor - c++

In a utility class file, I want to open a file to read or write it.
If I can't open it, I don't want to continue the process.
FileUtility::FileUtility(const char *fileName) {
ifstream in_stream;
in_stream.open(filename);
}
FileUtility fu = FileUtility("bob.txt");
fu.read();
fu.write();
File bob.txt doesn't exist, so I don't want method to read and write.
Is there a clean way to do it?

When construction of an object fails in C++, you should throw an exception, or propagate the exception from the failed construction of the subobject.
FileUtility(const char* filename) {
std::ifstream in_stream;
in_stream.exceptions(std::ios_base::failbit);
in_stream.open(filename); // will throw if file can't be opened
}
In the calling code you can choose to handle the exception:
try {
FileUtility fu = FileUtility("bob.txt");
} catch (std::ios_base::failure) {
printf("Failed to open bob.txt\n");
exit(EXIT_FAILURE);
}
// do other stuff
Or, if you don't catch the exception, the runtime will just call std::terminate(), which will print out its own error message, which may or may not be helpful:
terminate called after throwing an instance of 'std::ios_base::failure'
what(): basic_ios::clear
Aborted

There are generally four ways error state can be communicated from a callee to a caller:
1. Direct return value (return code or OUT parameter).
A return code is not possible for a constructor call, although an OUT parameter is. However, it's somewhat invasive to require every function to provide its return code or an OUT parameter for this purpose, so I don't like this solution in general, although it is certainly heavily used in various libraries and APIs. You could use this approach by adding a pointer or reference parameter to your constructor, to which the caller could provide the address of some local error variable, into which the constructor could store a possible return value. I don't recommend this.
2. Exceptions.
There is a somewhat polarized debate on the pros and cons of exceptions, in both C++ code and in other languages. I may take some downvotes for saying this, but my personal opinion is that exceptions should be avoided like the plague. See http://www.joelonsoftware.com/items/2003/10/13.html for someone who shares my view. But this is a workable solution if you're so inclined. See #Brian's answer for a good demonstration of this solution.
3. Object attribute.
The std::ifstream object actually does this, so you can leverage that. (Actually, from your example code, you define your std::ifstream as a local variable in the constructor, which implies it won't persist after the call, but since you call some kind of read() and write() methods on the constructed object, that implies that you do persist it after the call, so I'm going to assume the latter is the correct inference.) You can leverage that, by calling std::ifstream::is_open(). If you want to maintain encapsulation of the std::ifstream, you can define your own is_open() equivalent on FileUtility that will simply return in_stream.is_open();, again, assuming it is retained as an attribute on your FileUtility class.
struct FileUtility {
ifstream ifs;
FileUtility(const char* fileName);
bool is_open(void) const;
};
FileUtility::FileUtility(const char* fileName) { ifs.open(fileName); }
bool FileUtility::is_open(void) const { return ifs.is_open(); }
FileUtility fu = FileUtility("bob.txt");
if (!fu.is_open()) return 1;
Alternatively, you could create a whole new error state layer just for the FileUtility class, and propagate the std::ifstream error through that. For example:
struct FileUtility {
static const int ERROR_NONE = 0;
static const int ERROR_BADFILE = 1;
ifstream ifs;
int error;
FileUtility(const char* fileName);
};
FileUtility::FileUtility(const char* fileName) : error(ERROR_NONE) {
ifs.open(fileName);
if (!ifs.is_open()) { error = ERROR_BADFILE; return; }
}
FileUtility fu = FileUtility("bob.txt");
if (fu.error != FileUtility::ERROR_NONE) return 1;
These are reasonable solutions.
4. Global error state.
I wouldn't be surprised if some programmers were to respond with a "that sounds like a bad idea" reaction to this possible solution, but the truth is that many extremely successful and prominent code bases use this solution for communicating error state. Perhaps the best examples are the errno variable used by the C Standard Library (although it should be mentioned that errno sort of works in conjunction with direct return codes), and the GetLastError() system used by the Windows C API. I suppose some might argue that that's really the "C approach", and exceptions are the "C++ approach", but again, I avoid exceptions like the plague.
As an aside, multithreadedness is not a problem for this solution, because errno and GetLastError() both use thread-local error state, rather than true global error state.
I like this solution best, because it's simple, extremely uninvasive, and can easily be reused by different code bases, provided of course that you define the error framework (basically the thread-local variable and possibly the ERROR_NONE macro/global; see below) in its own library, in which case your code gains a consistency when it comes to error handling.
Example:
#define ERROR_NONE 0
thread_local int error = ERROR_NONE;
struct FileUtility {
static const int ERROR_BADFILE = 1;
ifstream ifs;
FileUtility(const char* fileName);
};
FileUtility::FileUtility(const char* fileName) {
ifs.open(fileName);
if (!ifs.is_open()) { error = ERROR_BADFILE; return; }
}
FileUtility fu = FileUtility("bob.txt");
if (error != ERROR_NONE) return 1;
This is the solution I'd recommend; otherwise I'd go with an object attribute solution.

Related

c++, dealing with exceptions from constructors

I have a class which is loaded from an external file, so ideally I would want its constructor to load from a given path if the load fails, I will want to throw an error if the file is not found/not readable (Throwing errors from constructors is not a horrible idea, see ISO's FAQ).
There is a problem with this though, I want to handle errors myself in some controlled manner, and I want to do that immediately, so I need to put a try-catch statement around the constructor for this object ... and if I do that, the object is not declared outside the try statement, i.e.:
//in my_class.hpp
class my_class
{
...
public:
my_class(string path);//Throws file not found, or other error error
...
};
//anywhere my_class is needed
try
{
my_class my_object(string);
}
catch(/*Whatever error I am interesetd in*/)
{
//error handling
}
//Problem... now my_object doesn't exist anymore
I have tried a number of ways of getting around it, but I don't really like any of them:
Firstly, I could use a pointer to my_class instead of the class itself:
my_class* my_pointer;
try
{
my_class my_pointer = new my_class(string);
}
catch(/*Whatever error I am interesetd in*/)
{
//error handling
}
The problem is that the instance of this object doesn't always end up in the same object which created it, so deleting all pointers correctly would be easy to do wrong, and besides, I personally think it is ugly to have some objects be pointers to objects, and have most others be "regular objects".
Secondly, I could use a vector with only one element in much the same way:
std::vector<my_class> single_vector;
try
{
single_vector.push_back(my_class(string));
single_vector.shrink_to_fit();
}
catch(/*Whatever error I am interesetd in*/)
{
//error handling
}
I don't like the idea of having a lot of single-element vectors though.
Thirdly, I can create an empty faux constructor and use another loading function, i.e.
//in my_class.hpp
class my_class
{
...
public:
my_class() {}// Faux constructor which does nothing
void load(string path);//All the code in the constructor has been moved here
...
};
//anywhere my_class is needed
my_class my_object
try
{
my_object.load(path);
}
catch(/*Whatever error I am interesetd in*/)
{
//error handling
}
This works, but largely defeats the purpose of having a constructor, so I don't really like this either.
So my question is, which of these methods for constructing an object, which may throw errors in the constructor, is the best (or least bad)? and are there better ways of doing this?
Edit: Why don't you just use the object within the try-statement
Because the object may need to be created as the program is first started, and stopped much later. In the most extreme case (which I do actually need in this case also) that would essentially be:
int main()
{
try
{
//... things which might fail
//A few hundred lines of code
}
catch(/*whaveter*/)
{
}
}
I think this makes my code hard to read since the catch statement will be very far from where things actually went wrong.
One possibility is to wrap the construction and error handling in a function, returning the constructed object. Example :
#include <string>
class my_class {
public:
my_class(std::string path);
};
my_class make_my_object(std::string path)
{
try {
return {std::move(path)};
}
catch(...) {
// Handle however you want
}
}
int main()
{
auto my_object = make_my_object("this path doesn't exist");
}
But beware that the example is incomplete because it isn't clear what you intend to do when construction fails. The catch block has to either return something, throw or terminate.
If you could return a different instance, one with a "bad" or "default" state, you could have just initialized your instance to that state in my_class(std::string path) when it was determined the path is invalid. So in that case, the try/catch block is not needed.
If you rethrow the exception, then there is no point in catching it in the first place. In that case, the try/catch block is also not needed, unless you want to do a bit of extra work, like logging.
If you want to terminate, you can just let the exception go uncaught. Again, in that case, the try/catch block is not needed.
The real solution here is probably to not use a try/catch block at all, unless there is actually error handling you can do that shouldn't be implemented as part of my_class which isn't made apparent in the question (maybe a fallback path?).
and if I do that, the object is not declared outside the try statement
I have tried a number of ways of getting around it
That doesn't need to be a problem. There's not necessarily need to get around it. Simply use the object within the try statement.
If you really cannot have the try block around the entire lifetime, then this is a use case for std::optional:
std::optional<my_class> maybe_my_object;
try {
maybe_my_object.emplace(string);
} catch(...) {}
The problem is that the instance of this object doesn't always end up in the same object which created it, so deleting all pointers correctly would be easy to do wrong,
A pointer returned by new is correct to delete. In the error case, simply set the pointer to null and there would be no problem. That said, use a smart pointer instead for dynamic allocation, if you were to use this approach.
single_vector.push_back(my_class(string));
single_vector.shrink_to_fit();
Don't push and shrink when you know the number of objects that are going to be in the vector. Use reserve instead if you were to use this approach.
The object creation can fail because a resource is unavailable. It's not the creation which fails; it is a prerequisite which is not fulfilled.
Consequently, separate these two concerns: First obtain all resources and then, if that succeeded, create the object with these resources and use it. The object creation as such in this design cannot fail, the constructor is nothrow; it is trivial boilerplate code (copy data etc.). If, on the other hand, resource acquisition failed, object creation and object use are both skipped: Your problem with existing but unusable objects is gone.
Responding to your edit about try/catch comprising the entire program: Exceptions as error indicators are better suited for things which are done in many places at various times in a program because they guarantee error handling (by default through an abort) while separating it from the normal control flow. This is impossible to do with classic return value examination, which leaves us with a choice between unreadable or unreliable programs.
But if you have long-lived objects which are created only rarely (in your example: only at startup) you don't need exceptions. As you said, constructor exceptions guarantee that only properly initialized objects can be used. But if such an object is only created at startup this danger is low. You check for success one way or another and exit the program which cannot perform its purpose if the initial resource acquisition failed. This way the error is handled where it occurred. Even in less extreme cases (e.g. when an object is created at the beginning of a large function other than main) this may be the simpler solution.
In code, my suggestion looks like this:
struct T2;
struct myEx { myEx(const char *); };
void exit(int);
T1 *acquireResource1(); // e.g. read file
T2 *acquireResource2(); // e.g. connect to db
void log(const char *what);
class ObjT
{
public:
struct RsrcT
{
T1 *mT1;
T2 *mT2;
operator bool() { return mT1 && mT2; }
};
ObjT(const RsrcT& res) noexcept
{
// initialize from file data etc.
}
// more member functions using data from file and db
};
int main()
{
ObjT::RsrcT rsrc = { acquireResource1(), acquireResource2() };
if(!rsrc)
{
log("bummer");
exit(1);
}
///////////////////////////////////////////////////
// all resources are available. "Real" code starts here.
///////////////////////////////////////////////////
ObjT obj(rsrc);
// 1000 lines of code using obj
}

How to use a variable in the same struct it's defined in?

I am making a rogue-like ASCII game and made a struct called "Armor" and I want to use the name variable in the struct to have the path to whatever the name is.
struct Armor {
bool equipped;
std::string name;
int getBuff(int buff) {
std::fstream item;
std::string line;
std::string response;
std::string value;
item.open("../Data/Items/" + name + ".item", std::fstream::in);
if (item.fail())
errorQuit("ERROR: There was a problem loading armor type .ITEM file."); // Error and quit function
while (!item.eof()) {
getline(item, line);
response = split(line, '=', 0); // Splits string
if (response == "buff" + std::to_string(buff)) {
value = split(line, '=', 1);
break;
}
}
item.close();
return std::stoi(value);
}
};
Then I called it like this:
Armor sword;
sword.name = "Wooden Sword";
int buff = sword.getBuff(1);
But this throws an Unhandled exception error.
I changed it so that getBuff takes 2 parameters, int buff and std::string itemName. and replaced name in the path with itemName;
Then I tried calling it like this:
Armor sword;
sword.name = "Wooden Sword";
int buff = sword.getBuff(1, sword.name);
But this throws the same error.
I'm confused as to why I can't use the name variable as it has already be defined. Is there any other way I can use the name variable like that?
I see you've just edited your comment to say you've figured your problem out, but I just want to add something else that may be helpful:
Without seeing how errorQuit() is defined, there's a potential problem in your getBuff() function. If the expression if (item.fail()) evaluates to true, the function may continue on trying to process the data (unless errorQuit() somehow breaks out of the program or something, which probably isn't the best approach).
Basically, testing for fail() may or may not provide the behavior you require in all scenarios, depending on what bits are set in the stream state. Implementations vary, but... if the file fails to open, failbit and/or badbit will be set, but not eofbit. getline() will see the error state and so it will not try to read from the stream when you call it. But that also means the eofbit will never be set!
There's lots of different "techniques" to file reading. Some people prefer an RAII approach. Others like looping on getline(). Or you could even just use good() to check the error state if you don't care what happened and simply want to know if everything is fine or not.
In any case, you might be interested in the info on this page: std::ios_base::iostate.
Thanks for all your help but I figured it out on my own.
I just made a stupid error that I overlooked like an idiot.
It is searching for buff + int (e.x. buff1) in the file but there are multiple lines that contain that word so I guessed that messed it up. I just made an adjustment to the if statement and it is working as expected.
Sorry to bother you!
your getBuf() function fails on some io-operation and throws an exception.You dont handle exceptions and thus the application quits with the appropriate message. Try surrounding the call to getBuf with try/catch (add the includes to iostream and stdexcept)
try {
int buff = sword.getBuff(1);
}
catch (const std::exception &e) {
std::cout << e.what() << std::endl;
}

Error handling when parsing text file to object

I want to parse a simple text file and create an object from the data it contains. I'm using C++11 for this (and I'm not fluent).
In case of any kind of error (e.g. missing file or invalid text) I wish to tell the caller of my parsing function what went wrong, providing information like what kind of error occurred and where in the file.
I don't consider exceptional that errors occur while parsing, so it seems exceptions are not the way to go.
I thought of returning a struct with all the info, including the resulting parsed object in case of success:
struct ParsingResult
{
bool success;
int errorCode;
int errorLine;
ParsedObject object;
}
However I'm not convinced by this solution because, in case of errors, I must still provide a ParsedObject. I can define a default constructor for that, of course, but by it's nature a ParsedObject makes sense only when the parsing is successful.
I could change ParsedObject to ParsedObject*, but I'm reluctant to use pointers when not necessary, and I wonder if this can be avoided.
My question: can you suggest a better solution to this problem? What is it?
struct Obj
{
// your object from the data...
}
struct ParseError
{
int errorCode;
int errorLine;
}
class Parser
{
ParseError m_error;
// other things
public:
bool parse(const std::string& filename, Obj& parsedObject)
{
// Open file, etc...
//parsedObject.property1 = some_value;
// if something is wrong, set m_error and return false;
// return true if ok
}
ParseError getLastError() { return m_error; }
}
// in your code
Parser p;
Obj o;
if(!p.parse("filename", o))
{
// ParseError = p.getLastError();
}
You can use a
unique_ptr<ParsedObject>
or
shared_ptr<ParsedObject>
whose default constructor can be compared to null in case of unsuccessful parsing.
Avoiding raw pointers will free you from having to free memory :)

C++ Exception Handling - Concrete Example

I've this program (parts of program not posted):
//Includes and functions
int main(int argc, char *argv[])
{
ifstream loc("achievements.loc", ios::binary);
getline(loc, header, static_cast<char>(1));
loc.seekg(15, ios::cur);
loc.read(reinterpret_cast<char*>(&subdirs), sizeof(subdirs));
for( int i = 0; i < nstrings; i++ )
{
loc.read(reinterpret_cast<char*>(&strid), sizeof(strid));
loc.read(reinterpret_cast<char*>(&stroffset), sizeof(stroffset));
curoffset = loc.tellg();
loc.seekg(strcodesbeg+16+stroffset);
getline(loc, codestring, '\0');
loc.seekg(curoffset);
}
}
I want to terminate the program if:
- The file is not opened;
- The header string, obtained by getline isn't equal to "String";
- Any of the read function fails;
- Any of the seekg fails;
- The strid, doesn't match with 1234.
How can I do this using C++ Exceptions? Should I use a single try{}catch(...){} block, creating functions that, for example, reads the data and sends EOF_REACHED on failure, or a try{}catch(var e){}catch(var2 e){}, a class, or any other way?
I understand the concept of the exceptions in simple function, but it gets complicated when there's a bigger program.
I didn't found too any c++ source code that uses try catch block explicitly in the main function, but works with exceptions. How this is possible?
The most verbose way to do this is to subclass a particular exception that will give you some context about what happened, for instance:
class FileNotOpenedException : public std::runtime_error {};
int main(int argc, char *argv[])
{
try
{
ifstream loc("achievements.loc", ios::binary);
if(!loc.is_open())
throw FileNotOpenedException;
// ...
}
catch(const FileNotOpenedException& e)
{
// ...
}
}
Note, however that using exceptions for expected error conditions is not necessarily good practice. Exceptions should be used only for truly "exceptional" conditions, that is something that is completely unexpected in your program, that you have no way of recovering from in the particular scope. The file not being opened above is a bad example. One of the read() or seekg() functions failing however may be more appropriate.
That said, it is possible to do what you are asking, and above is an example of one way to do it.

C++ - Where to throw exception?

I have some kind of an ideological question, so:
Suppose I have some templated function
template <typename Stream>
void Foo(Stream& stream, Object& object) { ... }
which does something with this object and the stream (for example, serializes that object to the stream or something like that).
Let's say I also add some plain wrappers like (and let's say the number of these wrappers equals 2 or 3):
void FooToFile(const std::string& filename, Object& object)
{
std::ifstream stream(filename.c_str());
Foo(stream, object);
}
So, my question is:
Where in this case (ideologically) should I throw the exception if my stream is bad? Should I do this in each wrapper or just move that check to my Foo, so that it's body would look like
if (!foo.good()) throw (something);
// Perform ordinary actions
I understand that this may be not the most important part of coding and these solutions are actually equal, but I just wan't to know "the proper" way to implement this.
Thank you.
In this case it's better to throw it in the lower-level Foo function so that you don't have to copy the validation and exception throwing code in all of your wrappers. In general using exceptions correctly can make your code a lot cleaner by removing a lot of data validation checking that you might otherwise do redundantly at multiple levels in the call stack.
I would prefer not to delay notifying an error. If you know after you have created the stream, that it is no good, why call a method that works on it? I know that to reduce code-redundancy you plan to move it further down. But the downside of that approach is a less-specific error message. So this depends to some extent on the source-code context. If you could get away with a generic error message at the lower-function level you can add the code there, this will surely ease maintanence of the code especially when there are new developers on the team. If you need a specific error message better handle it at the point of failure itself.
To avoid code redundancy call a common function that makes this exception/error for you. Do not copy/paste the code in every wrapper.
The sooner you catch the exceptiont the better. The more specific the exception is - the better. Don't be scared of including most of your code into a try catch blocks, apart fromt he declaration.
For example:
int count = 0;
bool isTrue = false;
MyCustomerObject someObject = null;
try
{
// Initialise count, isTrue, someObject. Process.
}
catch(SpecificException e)
{
// Handle and throw up the stack. You don't want to lose the exception.
}
I like to use helper functions for this:
struct StreamException : std::runtime_error
{
StreamException(const std::string& s) : std::runtime_error(s) { }
virtual ~StreamException() throw() { }
};
void EnsureStreamIsGood(const std::ios& s)
{
if (!s.good()) { throw StreamException(); }
}
void EnsureStreamNotFail(const std::ios& s)
{
if (s.fail()) { throw StreamException(); }
}
I test them immediately before and after performing stream operations if I don't expect a failure.
Traditionally in C++, stream operations don't throw exceptions. This is partly for historic reasons, and partly because streaming failures are expected errors. The way C++ standard stream classes deal with this is to set a flag on a stream to indicate an error has occurred, which user code can check. Not using exceptions makes resumption (which is often required for streaming ops) easier than if exceptions were thrown.