I solve the following problem: there is some file whose structure is a set of blocks. Each block has a header and body. The last block is marked with the corresponding identifier. To bypass the blocks in the file, I write my own iterator:

/** * @brief Single-pass input iterator. */ class BlockIterator : public std::iterator<std::input_iterator_tag, const DataBlock> { private: friend class FileReader; FileReader* reader; // Π’Π΅ΠΊΡƒΡ‰ΠΈΠΉ Π±Π»ΠΎΠΊ, Π½Π° ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΡƒΠΊΠ°Π·Ρ‹Π²Π°Π΅Ρ‚ ΠΈΡ‚Π΅Ρ€Π°Ρ‚ΠΎΡ€. std::unique_ptr<DataBlock> block; BlockIterator(FileReader* r, std::unique_ptr<DataBlock> b) noexcept : reader(r), block(std::move(b)) { /*NOP*/ }; public: BlockIterator& operator++() { auto nextBlockOffset = block->offset + block->headerSize + block->bodySize; block = reader->getBlockAt(nextBlockOffset); // ^^^ Ѐункция ΠΌΠΎΠΆΠ΅Ρ‚ Π²Ρ‹ΠΊΠΈΠ΄Ρ‹Π²Π°Ρ‚ΡŒ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅! return *this; } BlockIterator operator++(int) { auto retval = *this; ++(*this); return retval; } bool operator==(const BlockIterator& other) const { return reader == other.reader && block == other.block; } bool operator!=(const BlockIterator& other) const { return !(*this == other); } reference operator*() const { return *block; } }; 

When incrementing, the getBlockAt() function can throw an exception (for example, if the parsim is an invalid file). How in this case is better to do: is it necessary to guarantee the absence of exceptions when working with an iterator? If so, how to ensure the iterator is invalidated and an error is output?

  • It can add an isValidBlock method to your iterator or something to check it before using. Or if you received an exception, go to the next block, but then the external program does not recognize the error. - Unick
  • 6
    My IMHO. Since you inherit from std::iterator , you need to follow its ideology. An iterator assumes validity when pointing to existing data, and incorrect data (invalid file) is an exception for the iterator. An exception must throw an exception. Partly my opinion is confirmed by the fact that the iterators of the standard library are not declared as not generating exceptions. - user194374
  • @Unick Going to the next block does not make sense, if there is an error, then you can finish working with the file. For an additional function to check the validity you might think, but there is an additional overhead, so I wanted to know how they usually act in such cases. - Pavel Parshin
  • @kff, thanks, too, was inclined to such an opinion. - Pavel Parshin

2 answers 2

Since there is inheritance from std :: iterator <...>, it makes sense to preserve its ideology of handling such errors.

According to the latest published draft standard C ++ , you need to throw an exception:

Results for most expressions are undefined for singular values; the exceptions are that which holds the singular value ...

Page 856, p. 7

    Ignore the error can not be, you need to somehow inform about it always. How to report depends on where you use this iterator, if only in your code then you can either make a method to check the erroneousness of the current value of the iterator (in this case, when iterating the erroneous erroneous, you must throw an exception, or move the iterator to end () completed), if you want to use an iterator with a standard library like STL, then in the ideology of the iterator there is no possibility to return an error except through an exception, then you need to throw an exception, but it will be caught STL has no code and the one who uses them above. If you can’t throw exceptions at all for some reason, then you just need to just move the end to the end () when you move to an invalid block or try to skip one block if you can do this and find the next block, for example, by a special unique byte at the beginning of the header, then the processing program will consider that the processing is completely completed, although there will be unprocessed blocks, this will not lead to the collapse of the program, just the data will not be all processed, this behavior is often the case with different data handlers s, if they can not report an error when trying to skip the bad data and store somewhere information about errors in the statistics or log within their structures, then after work then you can find out how many broken blocks were missed and whether there were any errors.