I require a good substitute of std::string::npos
for std::iterator
which is has no relation to "next position after last valid address" ( end
).
Here is some background:
I have a method, where I need to find a certain value between two iterators and return iterator to a position NEXT to it (which may or may not be end
). It may happen that the method call is just a dummy and no action is required - in this case we simply return begin
. I also need some indication that we were unable to find the value in question and here lies the crux of the matter: I don't know how to indicate it.
Here is a simple example:
class FinderClass
{
public:
FinderClass(uint8_t* byte): byte_(byte) {}
std::iterator findEndOfFrame(std::iterator begin, std::iterator end)
{
if (byte_ == NULL)
{
return byte_;
}
std::iterator result = std::find(begin, end, *byte_);
if (result != end)
{
return ++result;
}
return ???;
}
private:
uint8_t* byte_;
}
And somewhere down the line we may use it this way:
std::vector<uint8_t> myVector;
myVector.push_back(1);
myVector.push_back(2);
myVector.push_back(3);
uint8_t val = 2;
FinderClass finder(&val);
std::iterator result = finder.findEndOfFrame(myVector.begin(), myVector.end());
if (/* no error */)
{
size_t len = std::distance(myVector.begin(), result);
}
In this case expected value of len
is 2. Had val
's value was set to 3
expected result would be 3 and in case of 4 - error. 0
is only appropriate result if NULL was provided in constructor.
Please keep in mind, that this is a very simplified version of more complex architecture. In reality, I cannot simply check what was provided in the constructor, since it is separated by multiple abstraction layers and the real FinderClass
implements an interface (and it's rather bizzare implementation, because in other implementation there is no option for NULL value for byte_
). At the point where we call std::distance
only a pointer to superclass is available.
I also do not use std::iterator
itself, but a derivative class, but since std::iterator
does not have some sort of npos
value defined, I thought that there is probably a good reason for it, so I didn't do it myself either. I only used std::iterator
in this example for simplicity.
So summing up : if end
cannot be used to indicate an error, what should be used instead?
Several considerations:
std::iterator
and simply return NULL on error) are considered "nuclear option, since it would require updating many other implementations and their unit tests. Given the constraints, I would either return a boost::optional<Iterator>
or a pointer to the next element (in which case you can return NULL
if there is no next element).
optional
is more expressive and safer of course, and requires less gerrymandering to convert the result back into an iterator.
Code using iterators is usually (and arguably should) pretty much agnostic of the actual type of iterator and instead just expects something with, roughly, incrementing and dereferencing operators. You don't specify whether the iterator has to be of a specific type or not, if not it's relatively easy to return a wrapper around an actual vector iterator which itself implements iterator behavior and also the extra functionality of having an invalid state. As said in the other answers though, going for optional<> is probably a better choice if possible as it clearly expresses what you actually mean. Anyway, pseudocode:
//template argument is the actual iterator type
template< class Iter >
class iterator : std::iterator< Iter::iterator_category,
Iter::value_type, .... >
{
public:
enum tag { invalid_tag };
//construct the invalid 'error' iterator
iterator( invalid_tag ) :
error( true )
{}
//construct actual iterator
iterator( Iter iter ) :
error( false ),
iter( iter )
{}
//forward all functions
reference operator * ()
{
assert( valid() );
return *iter;
}
....
//check validity
bool valid() const
{
return !error;
}
private:
bool error;
Iter iter;
};
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.