在给定指向元素的指针的情况下,您能找到列表元素的迭代器吗?

时间:2014-06-26 04:56:47

标签: c++ list iterator

问题可能是不言自明的,但是如果我有一个std::list<T>对象,是否有任何标准方法来获取元素的迭代器,给定一个指向元素的T*值?

如果T是用户定义的类型,它似乎取消引用指针并使用find_if来完成工作,但这对我来说似乎效率低下。如果您试图通过值在容器中查找元素,那么您需要遍历容器直到找到某些内容才有意义。但是如果你有一个指针,它直觉上应该有一个更直接的方法。我的基本理解让我觉得列表项的迭代器和它的指针之间应该有一对一的关系,因为列表在STL中是双重链接的,但我真的没有太多支持它。

我对C ++迭代器不太熟悉,所以如果有人能解释为什么有或没有办法做到这一点,那将会有所帮助。

编辑:Potatoswatter提供了一个很好的C ++ 11解决方案,但是如果有任何与C ++ 03兼容的解决方案,我仍然感兴趣。

4 个答案:

答案 0 :(得分:4)

在满足条件的范围内找不到迭代器没有标准算法。 find使用元素的值,但这根本不是同一个东西。带有比较地址的lambda的find_if可以正常工作。

编写通用版本很容易:

template< typename iter, typename t >
iter iterator_from_ptr( iter first, iter last, t * ptr ) {
    while ( first != last ) {
        // For C++03 compatibility, use &* first instead of addressof.
        if ( std::addressof( * first ) == ptr ) return first;
        ++ first;
    }
    return last;
}

用法:iterator_from_ptr( my_list.begin(), my_list.end(), ptr )

如你所述,效率低下,O(N)具体。更快的是违反C ++规则:您有一个指向对象的指针,该对象是std::list节点的成员,而list::iterator实际上是指向std::list节点的指针。但是(通常)没有办法从指针到成员到指针到整个对象。 (更不用说迭代器抽象阻碍了。)

答案 1 :(得分:0)

std::find()中的<algorithm>是否适合您?如果值类型已实现operator==,它应该有效。

#include <algorithm>
auto it = std::find(list.begin(), list.end(), *ptr);

答案 2 :(得分:0)

虽然我不推荐以下内容,但此功能可以满足您的要求。它依赖于列表实现的知识,所以它实际上只是一个有趣的练习,不应该依赖于生产代码:)

template <typename T>
typename list<T>::iterator iteratorFromPtr(T* a)
{
 auto offset = offsetof(_List_node<T>, _M_data);
 void* ptr = (void*)a;
 ptr -= offset;
 return _List_iterator<T>(static_cast<_List_node<T>*>(ptr));
}

编辑:用gcc-4.8.2测试。

答案 3 :(得分:-1)

您必须在类中定义/实现迭代器。如果我不想实现迭代器,我通常使用指针。