问题可能是不言自明的,但是如果我有一个std::list<T>
对象,是否有任何标准方法来获取元素的迭代器,给定一个指向元素的T*
值?
如果T
是用户定义的类型,它似乎取消引用指针并使用find_if
来完成工作,但这对我来说似乎效率低下。如果您试图通过值在容器中查找元素,那么您需要遍历容器直到找到某些内容才有意义。但是如果你有一个指针,它直觉上应该有一个更直接的方法。我的基本理解让我觉得列表项的迭代器和它的指针之间应该有一对一的关系,因为列表在STL中是双重链接的,但我真的没有太多支持它。
我对C ++迭代器不太熟悉,所以如果有人能解释为什么有或没有办法做到这一点,那将会有所帮助。
编辑:Potatoswatter提供了一个很好的C ++ 11解决方案,但是如果有任何与C ++ 03兼容的解决方案,我仍然感兴趣。
答案 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)
您必须在类中定义/实现迭代器。如果我不想实现迭代器,我通常使用指针。