首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >设计一个Iterator,以便在取消引用时抛出异常

设计一个Iterator,以便在取消引用时抛出异常
EN

Stack Overflow用户
提问于 2014-06-04 14:26:09
回答 3查看 1K关注 0票数 2

我需要找到一种方法来测试我编写的一个名为hpx::parallel::copy的函数中的异常处理。库中的其他函数(如hpx::parallel::transform )易于测试,因为可以传递谓词,其中抛出异常,但copy不接受谓词。

我认为我最好的解决方案是使用迭代器,以某种方式取消引用,尽管我不太确定如何执行this......any --其他解决这个问题的建议也是值得欢迎的。下面是我的问题的代码示例

代码语言:javascript
复制
//transform.cpp , testing exceptions
bool caught_exception = false;
    try {
        base_iterator outiter = hpx::parallel::transform(policy,
            iterator(boost::begin(c)), iterator(boost::end(c)), boost::begin(d),
            [](std::size_t v) {    //easy, predicate can be passed
                throw std::runtime_error("test");
                return v;
            });

        HPX_TEST(false);
    }
    //catching exceptions etc...
代码语言:javascript
复制
//copy.cpp, testing exceptions 
bool caught_exception = false;
    try {
        base_iterator outiter = hpx::parallel::copy(policy,
            iterator(boost::begin(c)), iterator(boost::end(c)), boost::begin(d)); //no predicate... how can I throw?
        HPX_TEST(false);
    }
    //catching exceptions etc..

更具体地说,我希望能够修改我想要的throw,以便测试多个场景,这意味着我不能使用抛出超出范围的实现或其他我无法控制的异常,我需要抛出特定的异常。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-06-11 20:12:34

一种与构建自己的迭代器不同的方法是构造已经存在的迭代器类的装饰器类。一个玩具例子可能是:

代码语言:javascript
复制
#include<functional>

/**
 * @brief Decorates an iterator to permit code injection before dereferencing 
 */
template<class T>
struct IteratorDecorator : public T {

  template<class V>
  IteratorDecorator(T iterator, V f) : T(iterator) , m_callback(f) {}

  typename T::value_type & operator*() {
      m_callback();
      return T::operator*();
  }

private:
  std::function<void()> m_callback;
};

/**
 * @brief Convenience function just for type deduction 
 */
template<class T, class V>
IteratorDecorator<T> decorate(T iterator, V v) {
  return IteratorDecorator<T>(iterator,v);
}

这可以在客户机代码中使用,如下所示:

代码语言:javascript
复制
int main()
{
  vector<int> ivec {1, 3, 5, 6};

  try {
    for_each(ivec.begin(),ivec.end(),[](int& x){ cout << x << endl; } );
    for_each(decorate(ivec.begin(), [](){ cout << "decorated : "; }), 
             decorate(ivec.end()  , [](){}),
             [](int& x){ cout << x << endl; }); 
    for_each(decorate(ivec.begin(), [](){ throw runtime_error("This one throws"); }), 
             decorate(ivec.end()  , [](){}),
             [](int& x){ cout << x << endl; } );
  } catch( exception& e) {
    cout << e.what() << endl;   
  }

  return 0;
}

如果您想对代码进行实验,您可以找到一个工作版本这里

票数 1
EN

Stack Overflow用户

发布于 2014-06-04 17:38:58

最简单的方法是使用对迭代器遍历的容器的反向引用来构造迭代器。每当您增加容器的end(),或减少它的begin(),或者当您取消对容器范围以外的任何内容的引用时,都会抛出一个异常。因为迭代器对容器有一个引用,所以您有所有这些信息。开销是每个迭代器的一个简单引用(或指针),以及operator--operator++operator*中的少量逻辑。

微软在他们的校验迭代器中使用这种方法,在使用他们的标准库时你可以打开它。给出了一个用实现表示的SafeSTL样本。他们的vector<T>看起来有点像这样:

代码语言:javascript
复制
template<class T>
class vector
{
public:
    class iterator
    {
    public:
         // regular iterator interface
    private:
         std::vector<T>* owner; // used by implementation to do checking
    };

    // rest of vector<T> interface
};
票数 1
EN

Stack Overflow用户

发布于 2014-06-11 19:24:33

或者,您可以做最简单的事情,编写一个值类型,其副本赋值操作符抛出(和/或移动赋值操作符、复制和移动构造函数,.)。

因为首先填充容器,如果需要,甚至可以选择抛出哪个值。比编写迭代器要少得多。

注意:我假设您想通过强制异常来测试您的算法。我认为TemplateRex的建议更多地针对迭代器,因为迭代器在运行时捕捉到意外的误用。请随时澄清。

示例实现:

最简单的值类型--它没有任何实际值,总是在复制或移动时抛出:

代码语言:javascript
复制
struct TrivialThrowOnCopy {
  TrivialThrowOnCopy() = default;
  TrivialThrowOnCopy(TrivialThrowOnCopy const &) {
    throw std::runtime_error("copy");
  }
  TrivialThrowOnCopy(TrivialThrowOnCopy&&) {
    throw std::runtime_error("move");
  }
};

或者,您可以在其中显式地告诉每个实例是否抛出:

代码语言:javascript
复制
struct ConfigurableThrowOnCopy {
    bool should_throw_;
    explicit ConfigurableThrowOnCopy(bool b = false) : should_throw_(b) {}
    ConfigurableThrowOnCopy(ConfigurableThrowOnCopy const &other) 
    : should_throw_(other.should_throw_) {
        if (should_throw_) throw std::runtime_error("copy");
    }
    ConfigurableThrowOnCopy(ConfigurableThrowOnCopy &&other) 
    : should_throw_(other.should_throw_) {
        if (should_throw_) throw std::runtime_error("move");
    }
};

或者每个_n_th副本都抛出:

代码语言:javascript
复制
struct CountingThrowOnCopy {
    static unsigned counter;
    // set CountingThrowOnCopy::counter = 5 to make the 5th copy throw
    CountingThrowOnCopy() = default;
    CountingThrowOnCopy(ConfigurableThrowOnCopy const &) {
        if (!--counter) throw std::runtime_error("copy");
    }
    CountingThrowOnCopy(ConfigurableThrowOnCopy&&) {
        if (!--counter) throw std::runtime_error("move");
    }
};

或上述任何一项,但包装一个实际值:

代码语言:javascript
复制
template <typename T>
struct ConfigurableThrowOnCopyT {
    T value_;
    bool should_throw_;
    explicit ConfigurableThrowOnCopyT(T const &t, bool b = false)
    : value_(t), should_throw_(b) {}
    ConfigurableThrowOnCopyT(ConfigurableThrowOnCopyT const &other)
    : value_(other.value_), should_throw_(other.should_throw_) {
        if (should_throw_) throw std::runtime_error("copy");
    }
    ConfigurableThrowOnCopyT(ConfigurableThrowOnCopyT &&other)
   : value(std::move(other.value_)), should_throw_(other.should_throw_) {
        if (should_throw_) throw std::runtime_error("move");
    }
    T& operator() { return value_; }
    T const& operator() const { return value_; }
};
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24040143

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档