简体   繁体   English

std :: iterator的错误指示器

[英]Error indicator for std::iterator

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 ). 我需要一个很好的std::string::npos std::iterator ,它与“最后一个有效地址之后的下一个位置”( 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 ). 我有一个方法,在这里我需要在两个迭代器之间找到一个确定的值,并将迭代器返回到它的下一个位置NEXT(它可以是也可以不是end )。 It may happen that the method call is just a dummy and no action is required - in this case we simply return begin . 可能会发生方法调用只是一个虚拟对象而无需执行任何操作的情况-在这种情况下,我们仅返回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. 在这种情况下, len期望值为2。如果val的值设置为3期望结果将为3,并且在出现4错误的情况下。 0 is only appropriate result if NULL was provided in constructor. 只有在构造函数中提供NULL时,才是0的适当结果。

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_ ). 实际上,我不能简单地检查构造函数中提供的内容,因为它是由多个抽象层分隔开的,并且真正的FinderClass实现了一个接口(这是非常奇怪的实现,因为在其他实现中, byte_ NULL值没有选择) 。 At the point where we call std::distance only a pointer to superclass is available. 在我们称为std::distance的点上,只有指向超类的指针可用。

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. 我也不使用std::iterator本身,而是使用派生类,但是由于std::iterator没有定义某种npos值,因此我认为可能有充分的理由,所以我没有这样做我自己也是。 I only used std::iterator in this example for simplicity. 为了简单起见,我在此示例中仅使用了std::iterator

So summing up : if end cannot be used to indicate an error, what should be used instead? 总结一下 :如果end不能用来表示错误,那么应该用什么代替呢?

Several considerations: 几个注意事项:

  1. Exceptions are forbidden by team's coding standards 团队的编码标准禁止例外
  2. Changes in interface (for example to change returned value to a pointer to std::iterator and simply return NULL on error) are considered "nuclear option, since it would require updating many other implementations and their unit tests. 接口的更改(例如,将返回的值更改为指向std::iterator的指针,并仅在错误时返回NULL)被视为“核选项,因为它将需要更新许多其他实现及其单元测试。
  3. C++11 is not avaialable C ++ 11不可用

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). 给定约束,我要么返回boost::optional<Iterator>要么指向下一个元素的指针(在这种情况下,如果没有下一个元素,则可以返回NULL )。

optional is more expressive and safer of course, and requires less gerrymandering to convert the result back into an iterator. 当然, optional是更具表现力和更安全的方法,并且不需要花太多时间就能将结果转换回迭代器。

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. 正如在其他答案中所说的那样,如果可能的话,选择optional <>可能是一个更好的选择,因为它清楚地表达了您的实际含义。 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; 
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM