Reputation: 471
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
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
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