anonymous
anonymous

Reputation: 471

Catch exception on variable declaration

I have a style issue in my code that I wonder if others have encountered. Say I have a class that either doesnt have a default constructor, or has a default constructor that I don't want to call (for performance and style reason). For sake of example, let's say this is a File object.

Now let's say that I have a file that contains a list of filenames to delete... And I want to do the following:

File f("foo");
for (const string& filenameToDelete : f.Lines())
    File(filenameToDelete).Delete();

File can throw FileNotFound in the constructor or in the Delete function. My code must throw on first failure to delete a file, but must not throw if the file "foo" doesnt exist (the absence of the file just means that there is nothing to delete).

I wish I could write something like this:

try { File f("foo"); } catch (FileNotFound) { return; }
for (const string& filenameToDelete : f.Lines())
    File(filenameToDelete).Delete();

but that obviously doesn't compile. I could do this:

unique_ptr<File> f;
try { f.reset(new File("foo")); } catch (FileNotFound) { return; }
for (const string& filenameToDelete : f->Lines())
    File(filenameToDelete).Delete();

but I somewhat dislike the fact that I need to do a memory allocation for a variable that could otherwise be stack allocated...

If I want to write the code with the somewhat arbitrary constraint that I don't do heap allocations, I can only think of doing it this way:

struct FileNotFoundToRethrow : public FileNotFound {};
try
{
    File f("foo");
    try
    {
        for (const string& filenameToDelete : f.Lines())
            File(filenameToDelete).Delete();
    }
    catch (FileNotFound)
    {
        throw FileNotFoundToRethrow();
    }
}
catch (FileNotFoundToRethrow) { throw; }
catch (FileNotFound) { return; }

I find this pretty ugly, it's hard to see that all I want to do is handle the FileNotFound exception thrown on the first line... Any better way?

Upvotes: 2

Views: 203

Answers (2)

Dialecticus
Dialecticus

Reputation: 16761

There is maybe a way for all those who feel particularly smarty, extending the lifetime with reference to const. But there are drawbacks. A class must have a null (or default) object, and, well, the reference is const.

File fooFile()
{
    try { return File("foo"); } catch (FileNotFound) { return File::Default; }
}

using it:

const File& foo = fooFile();

if (foo.IsDefault())
    return;

for (const string& filenameToDelete : f.Lines())
        File(filenameToDelete).Delete();

Upvotes: 1

Dialecticus
Dialecticus

Reputation: 16761

I'd do it with a flag

bool throwOnNotFound = false;

try
{
    File f("foo");

    throwOnNotFound = true;

    for (const string& filenameToDelete : f.Lines())
        File(filenameToDelete).Delete();
}
catch (FileNotFound)
{
    if (throwOnNotFound)
        throw;
}

Upvotes: 1

Related Questions