Search code examples
c++exceptionc++11throwhpx

Designing an Iterator to throw an exception on dereference


I need to find a way to test my exception handling in a function I wrote called hpx::parallel::copy. Other functions in the library such as hpx::parallel::transform are easy to test as a predicate can be passed in which throws an exception, but copy takes no predicate.

I think my best solution would be to use an iterator that throws on dereference somehow, though I'm not quite sure how to go about doing this......any other suggestions to solving this problem are welcome as well. Here is a code example of my problem

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

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

to be more specific, I want to be able to modify what exactly I want to throw in order to test multiple scenarios, this just means I can't use an implementation that throws out of range or other exceptions I can't control, I need to throw specific exceptions.


Solution

  • An approach different from constructing your own iterators would be to construct a decorator class of an already existing iterator class. A toy example may be:

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

    This may be used in client code like this:

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

    If you want to experiment with the code, you can find a working version here.