我正在使用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)
这是否符合规格?有没有人有实际经验?恕我直言,代码变得更加清晰,可能会实现微小的性能提升。
答案 0 :(得分:12)
直觉我认为它有效且完全初始化了吗?
您不能假设某个容器的迭代器可以取消引用容器的过去。根据C ++ 11标准的第24.2.1 / 5段:
正如指向数组的常规指针一样,可以保证指针值指向最后一个元素 对于任何迭代器类型,都有一个迭代器值指向超过a的最后一个元素 相应的序列。这些值称为past-the-end值。迭代器
i
的值 定义表达式*i
称为可解除引用。 图书馆永远不会假设过去的结果值 可解除引用。 [...]
答案 1 :(得分:3)
但是,迭代器的运算符*需要返回引用。直觉我认为它是有效的并完全初始化?
您的假设是错误的,解除引用容器外部的迭代器将导致UB。
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 ) {}