STL如何用非线性数据结构实现反向迭代器去引用
How the STL implement reverse iterator dereferencing with non-linear data structures?
使用指针时没有指针的字面含义。对下一段持保留态度。
实现反向迭代器很容易,使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)
你的问题不是很清楚。考虑一下把它整理一下。我甚至不确定我是否回答了你问的问题
- 不明白迭代器,引用和指针失效,一个例子
- boost_multi_index迭代器取消引用给出常量
- 为什么"std::uninitialized_copy"通常取消对未初始化内存的迭代器的引用不是未定
- 矢量迭代器不能与 std::shared_ptr<> 取消引用
- 无法取消引用值初始化迭代器
- std::remove() 按预期处理文字,但不能与取消引用的迭代器一起工作
- C++不能取消引用结束列表迭代器
- 如何取消引用向量迭代器
- 在此C++代码中,迭代器引用列表的哪个元素?
- 使用双迭代器引用映射中的列表
- 使用自动迭代器引用对象
- 另一个迭代器引用的对象被另一个迭代器删除
- C++ 使用迭代器引用连续值
- 正确取消对指针的迭代器引用
- 如何在C++中存储对 stl 容器元素的指针/迭代器引用
- 具有代理迭代器/引用和auto的容器
- 返回迭代器引用C++
- 迭代器引用 std::vector<std::unique_ptr<T>>
- 迭代器引用受控序列中的元素的要求
- 什么是自动迭代器引用的 C++98 等效项?