7

我将首先问这个问题,然后是动机,最后是一个按预期编译和执行的说明性代码示例。

问题

如果我可以保证迭代器在我需要使用它的持续时间内不会失效,那么持有指向迭代器的指针(例如指向 a 的指针list<int>::iterator)是否安全。

动机

我有多个容器,我需要从一个容器中的项目直接交叉引用到另一个容器中的相应项目,依此类推。一个容器中的项目可能并不总是在另一个容器中具有相应的项目。

因此,我的想法是将指向迭代器的指针存储在容器#1 中存储的元素中,以此类推。为什么?因为一旦有了迭代器,我不仅可以访问容器 #2 中的元素,而且如果需要,我还可以擦除容器 #2 中的元素等。

如果容器#2 中有对应的元素,我将在容器#1 的元素中存储一个指向迭代器的指针。否则,此指针将设置为 NULL。现在我可以快速检查指向迭代器的指针是否为 NULL,容器 #2 中没有对应的元素,如果非 NULL,我可以继续访问它。

那么,以这种方式存储指向迭代器的指针是否安全?

代码示例

#include <iostream>
#include <list>

using namespace std;

typedef list<int> MyContainer;
typedef MyContainer::iterator MyIterator;
typdef MyIterator * PMyIterator;

void useIter(PMyIterator pIter)
{
    if (pIter == NULL)
    {
    cout << "NULL" << endl;
    }
    else
    {
    cout << "Value: " << *(*pIter) << endl;
    }
}

int main()
{
    MyContainer myList;

    myList.push_back(1);
    myList.push_back(2);

    PMyIterator pIter = NULL;

    // Verify for NULL
    useIter(pIter);

    // Get an iterator
    MyIterator it = myList.begin();

    // Get a pointer to the iterator
    pIter = & it;

    // Use the pointer
    useIter (pIter);
}
4

5 回答 5

13

迭代器通常由 value处理。例如,begin()andend()将返回一个类型的实例iterator(对于给定的迭代器类型),而不是每次都iterator&返回一个值的副本。

您当然可以为此副本获取地址,但您不能期望对begin()end()将返回具有相同地址的对象的新调用,并且该地址仅在您自己持有迭代器对象时才有效。

std::vector<int> x { 1, 2, 3 };

// This is fine:
auto it = x.begin();
auto* pi = &it;

// This is not (dangling pointer):
auto* pi2 = &x.begin();

维护指向迭代器的指针几乎没有意义:迭代器已经是数据的轻量级句柄。进一步的间接性通常是设计不佳的标志。特别是在您的示例中,指针毫无意义。只需传递一个普通的迭代器。

于 2012-12-20T12:10:06.493 回答
2

迭代器的问题在于容器上有很多使它们无效的操作(这取决于所讨论的容器)。当您将迭代器保存到属于另一个类的容器时,您永远不知道何时会发生此类操作,也没有简单的方法可以发现迭代器现在无效。

此外,直接删除属于另一个类的容器中的元素是违反封装原则的。当您想删除另一个类的数据时,最好调用该类的公共方法,然后删除数据。

于 2012-12-20T12:09:38.283 回答
1

是的,这是安全的,只要您可以确保迭代器不会失效并且不会超出范围。

于 2012-12-20T12:09:49.910 回答
1

听起来很吓人。迭代器是一个对象,如果它离开范围,你的指针是无效的。如果您擦除容器 #2 中的对象,所有迭代器都可能变得无效(取决于容器),因此您的指针变得无用。

为什么不存储迭代器本身?对于容器 #1 中不引用任何内容的元素,存储 container2.end()。只要迭代器不失效,这很好。如果是,则需要重新生成映射。

于 2012-12-20T12:15:53.530 回答
1

是的,可以像处理其他类型一样处理指向迭代器的指针,但在您的示例中,这不是必需的,因为您可以简单地将原始迭代器作为引用传递。

一般来说,存储迭代器不是一个好主意,因为当您修改容器时,迭代器可能会变得无效。更好地存储容器并根据需要创建迭代器。

于 2012-12-20T12:29:34.280 回答