如何从该列表的元素中获取std :: list <T> :: iterator?

S.H*_*S.H 0 c++ iterator stl list c++11

给出一个std :: list

std::list< int > myList
Run Code Online (Sandbox Code Playgroud)

以及该列表中元素的引用(或指针)

int& myElement    |     int* pElement
Run Code Online (Sandbox Code Playgroud)

所以,基本上我知道那个元素的地址

如何有效地获得std::list<int>::iterator该元素?

一个缓慢但有效的例子是

const_iterator it
for( it = myList.begin(); it != &myElement; ++it)
{
    // do nothing, for loop terminates if "it" points to "myElem"
}
Run Code Online (Sandbox Code Playgroud)

有更快的方法吗?喜欢

const_iterator it = magicToIteratorConverter( myList, myElem )
Run Code Online (Sandbox Code Playgroud)

矢量的情况(但我需要清单):

对于矢量,您可以执行以下操作:

const int* pStart = &myVector[0] // address of first element
const int* pElement = &myElem; // address of my element
const idx = static_cast< int >( pElement- pStart ); // no need to divide by size of an elem

std::vector< int >::iterator it = myVector.begin() + idx;
Run Code Online (Sandbox Code Playgroud)

std :: list的案例:

Xat*_*ian 8

这实际上是一个很好的问题,恕我直言,遗憾的是没有标准的方法可以做到OP所要求的。如果您了解列表节点本质上是这样的

struct list_node {
    list_node* prev;
    list_node* next;
    T yourType;
}
Run Code Online (Sandbox Code Playgroud)

yourType如果您有一个指向该节点的指针而不搜索整个容器,那么没有默认方法可以到达该节点(迭代器是指向该节点的指针),这是很糟糕的。


由于 std 没有帮助你必须亲自动手:

#include <list>
#include <iostream>

//This is essentially what you are looking for:
std::list<int>::iterator pointerToIter (int* myPointer) {
    //Calculates the distance in bytes from an iterator itself
    //to the actual type that is stored at the position the
    //iterator is pointing to.
    size_t iterOffset = (size_t)&(*((std::list<void*>::iterator)nullptr));
    //Subtract the offset from the passed pointer and make an
    //iterator out of it
    std::list<int>::iterator iter;
    *(intptr_t*)&iter = (intptr_t)myPointer - iterOffset;
    //You are done
    return iter;
}

int main () {
    std::list<int> intList;
    intList.push_back (10);
    int* i1 = &intList.back ();
    intList.push_back (20);
    intList.push_back (30);
    int* i3 = &intList.back ();
    intList.push_back (40);
    intList.push_back (50);
    int* i5 = &intList.back ();

    std::cout << "Size: " << intList.size () << " | Content: ";
    for (const int& value : intList)
        std::cout << value << " ";
    std::cout << std::endl;

    intList.erase (pointerToIter (i1));
    intList.erase (pointerToIter (i3));
    intList.erase (pointerToIter (i5));

    std::cout << "Size: " << intList.size () << " | Content: ";
    for (const int& value : intList)
        std::cout << value << " ";
    std::cout << std::endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出(证明其按预期工作):

尺寸:5 | 内容:10 20 30 40 50
大小:2 | 内容:20 40

即使 std::list 的实现对列表节点使用不同的布局或向其中添加更多成员,这也能完美地工作。我还包含了生成的汇编代码,以查看该函数本质上被简化为myPointer - 0x100x10 = 1664 位机器上 2 个指针的大小)。

汇编器(至少带有-O1):

std::list<int>::iterator pointerToIter (int* myPointer) {
   0:   48 8d 47 f0             lea    rax,[rdi-0x10]
}
   4:   c3                      ret    
Run Code Online (Sandbox Code Playgroud)


Sir*_*Guy 5

a std::list<int>::iterator不是int*,你需要访问迭代器中的元素并获取其地址.另外,std::find_if为您处理大部分样板.

auto iter = std:find_if(myList.begin(), myList.end(),
                        [&myElement](const int & listElement)
                        { return &myElement == &listElement; });
Run Code Online (Sandbox Code Playgroud)

自己编写循环看起来像:

auto iter = myList.end();

for(auto i = myList.begin(); i != myList.end(); ++i)
    if(&*i == &myElement)
    {
        iter = i;
        break;
    }
Run Code Online (Sandbox Code Playgroud)

  • 刚看了C++ 14 25.2.5/1,我们似乎是 (2认同)