【问题标题】:How to construct a container of MyClass, where MyClass constructor can throw?如何构造一个MyClass的容器,MyClass的构造函数可以抛出哪里?
【发布时间】:2009-12-18 15:17:18
【问题描述】:

我有类似的东西:

#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));
  }
}

当 *dirIter 是非图像文件的 fs::path 时,MyImage 构造函数会抛出 MyInvalidFileException。

我希望 MyImage 和 ImageCollection 是不可变的。

我可以:

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;
}

当它抛出时会发生什么?双端队列中是否有僵尸 MyImage 或僵尸元素?或者这实际上是正确的方法吗? (即 push_back() 被中止并且没有创建 MyImage。)

我目前有一个混乱的解决方法:

// 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

其中 MyImage 使用 null QImage* 初始化,并且 loadPath() 在堆上创建 QImage。这迫使我到处进行空指针检查。我认为如果文件可以打开,应该有一个方法来拥有一个 QImage 的实例,如果文件不能打开,构造就会失败。

【问题讨论】:

  • 按常量引用而不是按值捕获。
  • 当 QDir 和朋友都在的时候,你为什么要使用 Boost 来管理路径?此外,deque 有点没用,因为 QList 在很多情况下都表现得非常好,并且提供了一个更干净、更易于使用的 API。
  • QList接口如何更好?在我看来完全一样。
  • 为什么图像构造函数必须抛出异常?它可以像 QImage 一样简单地创建一个“空”图像。
  • 出于(我猜的)典型原因,我想尽可能使用 STL,然后是 Boost,然后是 Qt。此外,通过这样做,我学到了很多关于处理 C++ 编程的外部库的知识。 @rpg - “null”是我已经在做的,但它不仅需要我处理 null 情况,我根本不需要 null 图像。我以后不会更改图像。我想这样设计,如果 QImage 无法打开图像,那么从一开始就永远不要构造并且永远不要插入到容器中。

标签: c++ exception constructor


【解决方案1】:

这取决于MyImage 我猜。如果 MyImage 的构造函数中存在异常,它应该会在您到达 push_back 方法之前失败。这是因为构造函数将在push_back 之前运行(这是合乎逻辑的,因为它需要一个值来传递方法)。因此,如果该步骤失败并引发异常,则永远无法到达 push_back

这里有一些提示:

【讨论】:

    【解决方案2】:

    如果MyImage(*dirIter) 失败,您将无法进入push_back,所以这不是问题。

    【讨论】:

      【解决方案3】:

      正如其他人已经提到的,如果 MyImage 构造函数抛出,那么您将永远无法到达 deque.push_back 函数,因此这不会是一个问题。此外,如果它确实进入push_back 函数并且由于某种原因抛出,那么您的双端队列对象将保持不变。如果操作失败,STL 不允许方法修改/损坏容器。我找不到任何关于 push_back 抛出 documentation 的信息,所以除非内存不足或其他极端情况,否则您可能不必担心。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-12-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-06-12
        • 1970-01-01
        相关资源
        最近更新 更多