views:

91

answers:

3

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.

+2  A: 

It depends on MyImage I guess. If there is an exception in the constructor of MyImage it should fail before you even reach the push_back method. This is because the constructor will be run before the push_back (which is logical, since it needs a value to pass the method). Thus if that step fails and exception is thrown, push_back will never be reached.

Here are some pointers:

Skurmedel
+1  A: 

If MyImage(*dirIter) fails you will not get into push_back so that's not a problem.

Andreas Brinck
+1  A: 

As others have already mention, if the MyImage constructor throws then you'll never reach the deque.push_back function so that will not be a problem. Also if it does make it into the push_back function and it throws for some reason, then your deque object will remain unchanged. The STL does not allow methods to modify/corrupt the container if the operation fails. I couldn't find anything about push_back throwing in the documentation, so you probably don't have to worry about that unless you run out of memory or some other extreme case.

cchampion