Jump to content
  • Advertisement
Sign in to follow this  
Giblodian

C++ Zombie flag altneratives

This topic is 3351 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

What are some eloquent ways to avoid fun stuff like segfaulting on objects that depend and operate on dynamically loaded data? A file class for example. Example (pseudo code):
class FileClass
public:
    File(const char *name)
    void write() 
    void read()
    void whateverone()
    void whatevertwo()
usually I have a bool indicating whether the constructor loaded the file correctly or not, then I check it in each of the methods but this is a PITA and sometimes I have to move the error checking down into derived classes. I could throw an exception, but it'd only be useful if I threw in an exit(1) -- and that's something I really hate doing especially with libraries -- otherwise I'd still have to use the zombie flag. Or am I wrong? I've thought about doing something like this
class FileClass
public:
    FileClass(FILE *)
    void write() 
    void read()
    void whateverone()
    void whatevertwo()
private:
    FileClass() 

FILE *file = fopen("nonexistant", "r+"); 
if (f != NULL) 
    FileClass o(file) 
loading and verifying the data outside the class, passing only something that's known to be valid. That way there are no worries of zombies. Are there any pitfalls with this approach? Any patterns worth looking at? What do you use? Note: FileClass is just a generic example.

Share this post


Link to post
Share on other sites
Advertisement
If you don't/can't use exceptions then one useful trick can be to wrap up the creation in a factory function, which will check that data was read successfully:


FileClass* open(const char* path)
{
FileClass* f = new FileClass(); // Does minimal work, nothing that can fail
const bool initOk = f.Init(path); // Does work which may fail
if (initOk)
return f;
else
delete f;
}


This gives you the opportunity to do work which may fail (Init()) in a construction-like way without using exceptions.

Exception-safe error handling and smart pointer use left as an exercise for the reader. Bonus points for making the c'tor and Init() private so this is the only way to create a new FileClass object.

Share this post


Link to post
Share on other sites
Quote:
Original post by Giblodian
I could throw an exception, but it'd only be useful if I threw in an exit(1)

You can't throw an exit(1). What do you mean exactly?
EDIT: sorry, I misread what you wrote.

Throwing an exception is often a valid option. You may have reasons not to, but can you elaborate on those?

Share this post


Link to post
Share on other sites
Yeah, I'd do the same as OrangyTang.
If the class's function depends on if the constructor fails, then it's best to have an init function for it, since you can't use it anyway if it failed you have to get rid of it or if it wasn't dynamicly allocated, exit the function using it.
For dynamic allocations, I usually create a function like OrangyTang wrote but as a static one inside the class.. like FileClass::OpenFile( "..." );

Share this post


Link to post
Share on other sites
You should really only throw an exception if your code runs into a situation it can't or shouldn't handle. A file class trying to open a file that doesn't exist isn't exceptional behavior, since that's just the nature of file classes and other objects which bind themselves to external resources which may or may not exist, or have other permissions assigned to them preventing you from performing certain actions. While you may want to open a particular file, the object should be able to gracefully deal with the case where the file doesn't exist by returning an error or entering a fail state.

Share this post


Link to post
Share on other sites
Quote:
Original post by Zipster
A file class trying to open a file that doesn't exist isn't exceptional behavior, since that's just the nature of file classes and other objects which bind themselves to external resources which may or may not exist.


Actually, I would say that it is exceptional behaviour. Most of the time I'd expect to get a valid path to an "openable" file. There's no point in creating a useless file object. It would be even more exceptional in my mind if the file couldn't be opened for writing.

I guess it's a matter of taste. std::ifstream clearly agrees with you.

Share this post


Link to post
Share on other sites
Quote:
Original post by the_edd
Actually, I would say that it is exceptional behaviour. Most of the time I'd expect to get a valid path to an "openable" file. There's no point in creating a useless file object. It would be even more exceptional in my mind if the file couldn't be opened for writing.

As the user of the file class, I would also expect the file to be opened or created. If perhaps this was a critical resource like the model or texture package then I might throw an exception if the file couldn't be opened. But as far as the file class itself is concerned, this sort of thing happens all the time. It isn't outside the realm of what the file class can reasonably deal with, which is what I meant by "exceptional". It's isn't an uhoh-something-went-wrong-and-my-world-is-collapsing-around-me situation :)

Plus the file class isn't necessarily useless at that point. The object itself should remain in a perfectly valid state so that you can do something like this:
FileClass file("this_file_doesn't_exist.txt");
if(!file.is_open())
file.open("this_file_does_exist.txt");

Share this post


Link to post
Share on other sites
Personally I'd go with unopenable files being exceptional cases and have some other mechanisms to check if a file exists/is accessible. A file object shouldn't have to deal with existing in a world where the file it's supposed to represent doesn't exist/can't be accessed; the client should query some other object like a File System or Directory or a static method in FileClass or what have you before attempting to open a file.

That way if you as the client are in a situation where you know the file should exist/be accessible and have no backup plans if it's not you get an exception if that happens, and if you know it may not exist you query for it first and go to plan B if you must.

Share this post


Link to post
Share on other sites
Quote:
Original post by Zipster
As the user of the file class, I would also expect the file to be opened or created.

Well, I'd say it depends on how the class is used.

If I put up a GUI with an "open file" dialog such that it was impossible to provide a non-existent file, failing to open that file would be exceptional.

Quote:
If perhaps this was a critical resource like the model or texture package then I might throw an exception if the file couldn't be opened.

What difference does it make if the resource is critical or not?

Quote:

But as far as the file class itself is concerned, this sort of thing happens all the time.

If you mean that it's certainly a case that should be handled, I completely agree.

Quote:
It isn't outside the realm of what the file class can reasonably deal with, which is what I meant by "exceptional". It's isn't an uhoh-something-went-wrong-and-my-world-is-collapsing-around-me situation :)

Again I agree, but I don't think an exception implies that "uhoh" situation. I guess your mindset is just different.

Quote:
Plus the file class isn't necessarily useless at that point. The object itself should remain in a perfectly valid state so that you can do something like this:
FileClass file("this_file_doesn't_exist.txt");
if(!file.is_open())
file.open("this_file_does_exist.txt");


You could do the same with a try/catch block. I don't get what you mean here.

But I think we have different ideas about the purpose of the class. I guess you're thinking of it as something which is responsible for looking at both a file's data and also querying its file-system attributes, where as I'm looking at it as something that's merely for reading the data.

If I wanted something to do both, I'd probably do something like:


fs_entry somefile("somefile.txt"); // never throws
cout << somefile.exists() << endl;

data_stream &ds = somefile.open(); // may throw


All this does beg the question "why not use std::ifstream?", though.


Regardless of the merits of each approach, I still don't get why throwing an exception isn't an *option* for the O.P.

Share this post


Link to post
Share on other sites
First, I'm just a hobbyist, so no need to worry about me contaminating the code pool or whatever.

I simply do not like exceptions. Always seems to turn into a mess when I use them. Something like this

class FileClass
{
public:
static FileClass* create(const char *name)
{
FILE *f = fopen(name, "r+");
if(f != NULL)
{
FileClass *r = new FileClass();
r->file = f;
return r;
}
else return NULL;
}
~FileClass();
private:
FileClass() {}
FILE *file;
};

int main()
{
FileClass *o = FileClass::create("doesntexist");
if(o == NULL) {
//whatever
}
}


or the method I originally mentioned just seem much simpler than fiddling around with throw,try,catch everywhere. May not be correct thought, but it does seem to give the appearance of working.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!