是 - >第二个为迭代器my_map.end()定义的?

时间:2013-04-28 20:41:08

标签: c++ stl iterator

我正在使用std::map<std::string, MyClass* >

我想测试my_map.find(key)是否返回了特定的指针。

现在我正在做;

auto iter = my_map.find(key);
if ((iter != my_map.end()) && (iter->second == expected)) {
    // Something wonderful has happened
}

但是,迭代器的operator *需要返回引用。直觉我认为它是有效的并完全初始化?如果是这样,my_map.end()->second将是NULL,并且(因为NULL从未预料到),我可以将if语句减少为:

if (iter->second == expected)

这是否符合规格?有没有人有实际经验?恕我直言,代码变得更加清晰,可能会实现微小的性能提升。

4 个答案:

答案 0 :(得分:12)

  

直觉我认为它有效且完全初始化了吗?

您不能假设某个容器的迭代器可以取消引用容器的过去。根据C ++ 11标准的第24.2.1 / 5段:

  

正如指向数组的常规指针一样,可以保证指针值指向最后一个元素   对于任何迭代器类型,都有一个迭代器值指向超过a的最后一个元素   相应的序列。这些值称为past-the-end值。迭代器i的值   定义表达式*i称为可解除引用。 图书馆永远不会假设过去的结果值   可解除引用。 [...]

答案 1 :(得分:3)

  

但是,迭代器的运算符*需要返回引用。直觉我认为它是有效的并完全初始化?

您的假设是错误的,解除引用容器外部的迭代器将导致UB。

24.2迭代器要求[iterator.requirements]

24.2.1一般[iterator.requirements.general]

  

7大多数在数​​据结构上运行的库的算法模板都有使用范围的接口。   范围是一对指定计算开始和结束的迭代器。范围[i,i)是一个   空的范围;通常,范围[i,j)是指以元素开始的数据结构中的元素   由i指向,但不包括j指向的元素。范围[i,j]有效当且仅当   j可以从i到达。 未定义库中函数应用于无效范围的结果。

答案 2 :(得分:2)

即使不检查规范,您也可以轻松地看到取消引用end处的迭代器必须无效。

完全自然的实现(vector<> de-factor 标准实现)是end()字面上的一个内存指针,其值为ptr_last_element + 1 },即指向下一个元素的指针值 - 如果有下一个元素。

您不可能允许取消引用end迭代器,因为它可能是一个指向最终指向堆中的下一个对象的指针,或者可能是溢出保护区(因此您可以取消引用随机内存),或者超过堆的末尾,并且可能在进程的内存空间之外,在这种情况下,在解除引用时可能会出现访问冲突异常。

答案 3 :(得分:1)

如果iter == my_map.end (),则取消引用它是未定义的行为;但你不是在这里做的。

auto iter = my_map.find(key);
if ((iter != my_map.end()) && (iter->second == expected)) {
    // Something wonderful has happened
}

如果iter != my_map.end()为false,则表达式的后半部分(iter->second == expected)将不会被执行。

阅读“短期评估”。 指针的类似有效代码:

if ( p != NULL && *p == 4 ) {}