STL如何用非线性数据结构实现反向迭代器去引用

How the STL implement reverse iterator dereferencing with non-linear data structures?

本文关键字:迭代器 引用 实现 何用 非线性 数据结构 STL      更新时间:2023-10-16

使用指针时没有指针的字面含义。对下一段持保留态度。

实现反向迭代器很容易,使rbegin()==end()和rend()==begin()具有线性数据结构,因为您可以将反向访问映射到迭代器指向的元素的BEFORE(例如,rbegin)指向end(),但访问end()-1)。但是,当处理树或哈希表时,我应该如何处理这种映射?我目前正在使用"OneAfterTheLast"标志来标记转发迭代会话的结束,我正在考虑手动实现反向迭代器逻辑,并添加"OneBeforeTheFirst"标志。这个设计好吗?

此外,在找不到键的情况下,find()方法应该返回一个"OneAfterTheLast"迭代器,或者我的check方法应该检查两个标志(OneAfterTheEnd和OneBeforeTheFirst)?

这是我的公共接口,仅供参考,仍然没有反向迭代器方法。容器类和迭代器类都是不透明的。

typedef PWError (*PWDictCallback)(const char *key, const char *val, void *extra);
PWError pwdictCreate(PWDict **dictRef, PWDictImplementationId id, size_t elements);
PWError pwdictCreateWithImplementation(PWDict **dictRef, const PWDictImplementation* impl, size_t elements);
void pwdictDestroy(PWDict *dict);
unsigned int pwdictSize(const PWDict *dict);
unsigned long pwdictSizeInBytes(const PWDict *dict);
PWError pwdictGet(const PWDict *dict, const char *key, char *output, size_t size);
PWError pwdictSet(PWDict *dict, const char *key, const char *value);
PWError pwdictRemove(PWDict *dict, const char *key);
PWError pwdictIteratorCreate(PWDictIterator **itRef, PWDict *dict);
PWError pwdictIteratorBegin(PWDictIterator *it);
int pwdictIteratorIsEnd(PWDictIterator *it);
void pwdictIteratorDestroy(PWDictIterator *it);
PWError pwdictFind(PWDictIterator *it, const char *key);
const char *pwdictIteratorGetKey(const PWDictIterator *it);
const char *pwdictIteratorGetValue(const PWDictIterator *it);
PWError pwdictIteratorSetValue(PWDictIterator *it, const char *value);
PWError pwdictIteratorRemove(PWDictIterator *it);
PWError pwdictIteratorNext(PWDictIterator *it);
PWError pwdictClear(PWDict *dict);
PWError pwdictAdd(PWDict *dict, const PWDict *from);
int pwdictIsEqual(const PWDict *d1, const PWDict *d2);
PWError pwdictForeach(PWDict *dict, PWDictCallback cb, void *extra);
void pwdictPrint(const PWDict *dict, int logLevel);

std::reverse_iterator通过保持一个普通迭代器来实现,但(概念上)在解引用时返回*(i-1)。您也可以这样做,或者直接使用std::reverse_iterator

来自C++03标准:

反向迭代器与其对应的迭代器i之间的基本关系由标识&*(reverse_iterator(i)) == &*(i - 1)建立。

这种映射是由这样一个事实决定的,即尽管总是有一个指针经过数组的末尾,但在数组的开头之前可能没有有效的指针。

(第二句从C++11标准中删除)

反向迭代器的实现方式通常是,容器内部有一个普通迭代器,它指向反向迭代程序逻辑引用的项之后的元素。这样,内部迭代器(可以使用reverse_iterator::base()获得)总是指向容器内或容器的端部。所以它总是有效的。当取消引用反向迭代器时,只需递减基数(如果有双向迭代器,可以这样做)并取消引用。

我假设您的接口中有一个可工作的双向迭代器,因为您提到了这是您的需求的一部分。所以,我假设有一个pwdictIteratorPrev()函数。此外,反向迭代器功能需要临时操作私有迭代器,因此我还假设还有更多的功能,例如复制迭代器的能力和比较迭代器。

因此,这些功能(无论是否在公共界面中)应该是可用的。我相信它们可能很容易写出来:

int pwdictIteratorIsEqual(PWDictIterator* it1, PWDictIterator* it2);
PWError pwdictIteratorCopy(PWDictIterator* dst, PWDictIterator const* src);
PWError pwdictIteratorEnd(PWDictIterator* it);

您的反向迭代器可能如下所示(没有显示错误处理):

struct PWDictRIterator {
    PWDictIterator* base;
    PwDict* dict;
};
typdef struct PWDictRIterator PWDictRIterator;
PWError pwdictRIteratorCreate(PWDictRIterator **ritRef, PWDict *dict)
{
    PWError err;
    PWDictRIterator* riter = malloc(sizeof(PWDictRIterator));  // or however you want to allocate
    if (riter) {
        riter->dict = dict;
        err = pwdictIteratorCreate( &riter->base, dict);
    }
    return err;
}
PWError pwdictRIteratorBegin(PWDictRIterator *rit)
{
    return pwdictIteratorEnd(rit->base);
}
int pwdictRIteratorIsEnd(PWDictRIterator *rit)
{
    PWDictIterator* begin;
    PWError err;
    err = pwdictIteratorCreate( &begin, rit->dict);
    err = pwdictIteratorBegin(&begin);
    // there needs to be some way to do the following somehow - 
    //  I assume a plain old pointer compare won't do the trick
    int is_end = pwdictIteratorIsEqual( rit->base, begin);
    pwdictIteratorDestroy(begin);
    return is_end;
}

const char* pwdictRIteratorGetKey(onst PWDictRIterator *rit)
{
    // remember - to 'derefernce' a reverse iterator, we have to
    //  decrement the base first
    PWDictIterator* tmp;
    // all error handling elided...
    PWError err;
    err = pwdictIteratorCreate( &tmp, rit->dict);
    // we need a temporary iterator, so the base can stay the same
    //  I assume that some sort of copy operation can be created
    //  for iterators - it might not need to be part of the public interface
    err = pwdictIteratorCopy(tmp,rit->base);   
    err = pwdictIteratorPrev(tmp);
    const char* result = pwdictIteratorGetKey(tmp);
    pwdictIteratorDestroy(tmp);
    return result;
}

PWError pwdictRIteratorNext(PWDictRIterator *rit)
{
    return pwdictIteratorPrev(rit->base);
}
PWError pwdictRIteratorPrev(PWDictRIterator *rit)
{
    return pwdictIteratorNext(rit->base);
}
// further functions are basically variations on the above theme...

为了与C++中到处使用的迭代器模式保持一致,rbegin()应该创建一个指向最后一个元素(end()之前的元素)的迭代程序,rend()应该建立一个指向开始之前元素(begin()之前)的迭代器。

这允许您使用与循环的典型迭代器相同的逻辑:

for ([iterator type] i = something.rbegin(); i != rend(); ++i)

你的问题不是很清楚。考虑一下把它整理一下。我甚至不确定我是否回答了你问的问题