I have something like:
#include "MyImage.hpp" // MyImage wraps the Qt library image class
namespace fs = boost::filesystem;
class ImageCollection {
public:
ImageCollection(const char* path);
private:
const fs::path path_;
deque<MyImage> instanceDeque_;
}
ImageCollection(const char* path) :
path_(fs::is_directory(path) ?
fs::complete(path) :
fs::complete(path).parent_path()) /* Can I even do this? */
{
/*** code in question ***/
fs::directory_iterator endIter;
for(fs::directory_iterator dirIter(path_); dirIter != endIter; dirIter++) {
instanceDeque_.push_back(MyImage(*dirIter));
}
}
The MyImage constructor throws a MyInvalidFileException when *dirIter is a fs::path to a non-image file.
I’d like MyImage and ImageCollection to be immutable.
Can I:
try {
instanceDeque_.push_back(MyImage(*dirIter));
}
catch(const MyInvalidFileException& e) { // oops, tnx Nemanja T.
// remember *dirIter in a list of non-Image files, to use later
continue;
}
What happens when it throws? Is there a zombie MyImage or a zombie element left in the deque? Or is this actually the right way to do it? (i.e. the push_back() is aborted and no MyImage is created.)
I currently have a messy workaround:
// load up an empty MyImage, which I'd rather not do
instanceDeque_.push_back(MyImage());
for(fs::directory_iterator dirIter(path_); dirIter != endIter; dirIter++) {
MyImage& attemptImage = instanceDeque_.back();
bool success = attemptImage.loadPath(*dirIter); // "fill" the empty MyImage
if (success)
instanceDeque_.push_back(MyImage()); // prepare another empty MyImage
}
instanceDeque_.pop_back(); // discard the empty MyImage
Where MyImage is initialized with a null QImage*, and loadPath() creates a QImage on the heap. This forces me to have null pointer checks everywhere. I figure there should be a way to have an instance of QImage if the file can be opened, and the construction to just fail if the file can’t.
It depends on
MyImageI guess. If there is an exception in the constructor of MyImage it should fail before you even reach thepush_backmethod. This is because the constructor will be run before thepush_back(which is logical, since it needs a value to pass the method). Thus if that step fails and exception is thrown,push_backwill never be reached.Here are some pointers:
constructor that fails?
Lite: How should I handle resources
if my constructors may throw
exceptions?