std::iterator 的错误指示器

Error indicator for std::iterator

我需要用 std::string::npos 代替 std::iterator,这与 "next position after last valid address" (end).

无关

这是一些背景:

我有一个方法,我需要在两个迭代器和 return 迭代器之间找到某个值到它旁边的位置(可能是也可能不是 end)。方法调用可能只是一个虚拟对象,不需要任何操作——在这种情况下,我们只是 return begin。我还需要一些指示,表明我们无法找到有问题的值,这就是问题的症结所在:我不知道如何指示它。

这是一个简单的例子:

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

我们可以这样使用它:

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

在这种情况下,len 的预期值为 2。如果 val 的值设置为 3,预期结果将是 3,如果是 4 - 错误。 0 只有在构造函数中提供 NULL 时才是合适的结果。

请记住,这是更复杂架构的一个非常简化的版本。实际上,我不能简单地检查构造函数中提供的内容,因为它被多个抽象层分隔开,并且真正的 FinderClass 实现了一个接口(这是相当奇怪的实现,因为在其他实现中没有 NULL 选项byte_ 的值)。在我们调用 std::distance 的地方只有指向 superclass 的指针可用。

我也不使用 std::iterator 本身,而是使用派生的 class,但是由于 std::iterator 没有定义某种 npos 值,我认为可能有一个很好的理由,所以我自己也没有这样做。为简单起见,我在此示例中仅使用了 std::iterator

所以总结:如果end不能用来指示错误,应该用什么代替?

几个注意事项:

  1. 团队的编码标准禁止例外
  2. 接口中的更改(例如将 returned 值更改为指向 std::iterator 的指针,并在出错时简单地 return NULL)被视为“核选项,因为它需要更新许多其他实现及其单元测试。
  3. C++11 不可用

鉴于限制,我会 return 一个 boost::optional<Iterator> 或指向下一个元素的指针(在这种情况下,如果没有,你可以 return NULL下一个元素)。

optional 当然更具表现力和安全性,并且需要更少的不公正划分将结果转换回迭代器。

使用迭代器的代码通常(并且可以说应该)几乎不知道迭代器的实际类型,而只是期望具有大致递增和取消引用运算符的东西。您没有指定迭代器是否必须是特定类型,如果不是,那么 return 一个实际向量迭代器的包装器相对容易,它本身实现迭代器行为以及具有无效的额外功能状态。正如在其他答案中所说,如果可能的话,选择 optional<> 可能是一个更好的选择,因为它清楚地表达了您的实际意思。不管怎样,伪代码:

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