在整个microsofts stl实现过程中,几乎所有迭代器在使用前都已展开。
例如,for_each看起来像这样:
template <class _InIt, class _Fn>
_Fn for_each(_InIt _First, _InIt _Last, _Fn _Func) { // perform function for each element [_First, _Last)
_Adl_verify_range(_First, _Last);
auto _UFirst = _Get_unwrapped(_First);
const auto _ULast = _Get_unwrapped(_Last);
for (; _UFirst != _ULast; ++_UFirst) {
_Func(*_UFirst);
}
return _Func; }
_Adl_verify_range首先检查
#if _HAS_IF_CONSTEXPR
template <class _Iter>
_NODISCARD constexpr decltype(auto) _Get_unwrapped(_Iter&& _It) {
// unwrap an iterator previously subjected to _Adl_verify_range or otherwise validated
if constexpr (is_pointer_v<decay_t<_Iter>>) { // special-case pointers and arrays
return _It + 0;
} else if constexpr (_Unwrappable_v<_Iter>) {
return static_cast<_Iter&&>(_It)._Unwrapped();
} else {
return static_cast<_Iter&&>(_It);
}
}
#else // ^^^ _HAS_IF_CONSTEXPR / !_HAS_IF_CONSTEXPR vvv
template <class _Iter, enable_if_t<_Unwrappable_v<_Iter>, int> = 0>
_NODISCARD constexpr decltype(auto) _Get_unwrapped(_Iter&& _It) {
// unwrap an iterator previously subjected to _Adl_verify_range or otherwise validated
return static_cast<_Iter&&>(_It)._Unwrapped();
}
它似乎想要衰减迭代器,或者将其强制转换为右值引用。
所以我的问题是为什么视觉使用这种范式?据我所知,GCC并没有这样做。
编辑
根据要求,提供迭代器的源代码_展开的
_NODISCARD constexpr _Ptr _Unwrapped() const noexcept {
return _Myptr;
}
_Myptr在迭代器本身中定义,并且只是一个原始指针:
template <class _Ptr>
class unchecked_array_iterator {
...
private:
_Ptr _Myptr; // underlying pointer
}
匿名用户
如果我理解正确,这是一个调试功能。
包装的迭代器包含额外的信息,允许实现验证各种前提条件,例如两个迭代器是否构成有效范围、迭代器是否未失效、迭代器仅与它引用的元素一起使用<代码>\u Adl\u verify\u range就是这样一种检查。
但是,当算法中实际使用迭代器时,实现不希望产生验证的开销(这会发生在每个
操作中)。它将迭代器解包为不具有安全功能的版本。通常这意味着,未包装的版本只是一个指针(不一定是裸的,但包装在类中)。
在Release版本中,算法本身可以得到很好的优化,因为只涉及非常简单的类型,没有检查,但初始安全检查可以保留或可以省略,如开发人员所愿。
为什么VC包装迭代器?
这是一种设计选择。实际上,对于类似数组的类型,比如std::array
和std::vector
,迭代器可以是一个简单的typedef
到T*
,这很好地满足了迭代器语义,GNU stdlibc就是这样实现它的。但从标准的角度来看,迭代器是一个类似指针的对象,但不一定是指针。所以
>
假设它是一个指针将是一个错误,并可能导致不可移植的代码(示例)。
包装迭代器允许迭代器调试(请参阅_ITERATOR_DEBUG_LEVEL
)。例如,这里有一个调试运算符
:
_CONSTEXPR17 _Array_const_iterator& operator++() {
_STL_VERIFY(_Ptr, "cannot increment value-initialized array iterator");
_STL_VERIFY(_Idx < _Size, "cannot increment array iterator past end");
++_Idx;
return *this;
}
为什么VC展开迭代器?
>
这是一种性能优化。
- 在调试模式下,检查一次先决条件会导致更快的代码(调试模式已经慢了10倍,所以即使在调试模式下,性能仍然很重要)
我只是想知道为什么是java。util。扫描器实现java。util。迭代器? 实现删除方法,并抛出一个不支持的操作异常。 但是一个类在实现接口时,不应该履行接口的契约吗? 实现
在Java8中,我们有类stream ,奇怪的是,它有一个方法 所以您希望它实现interface Iterable ,这恰恰需要这个方法,但事实并非如此。 当我想使用foreach循环对流进行迭代时,我必须执行如下操作 我是不是漏了什么?
我可以看到返回。但是现在已经添加到C++20标准中,为什么返回?cppreference指定: 返回值 等于last的迭代器。 这个选择背后的理性是什么? 与相比,用例的优势是什么?
超级和蔼的面试官,说英语也很好听 1.自我介绍 2.介绍项目 3.项目相关问题 3.1 说一下缓存数据库不一致问题,你怎么解决的?为什么? 3.2 说一下redis的特点?支持多大的qps?延迟? 4. 算法题:LeetCode 200. 岛屿数量。 感觉微软考察重点就是算法题,自己用dfs啪一下做出来了,面试官让说说dfs的pros & cons,答:快、简单,但有爆栈的可能。问怎么解决
问题内容: 在Java 5及更高版本中,您具有foreach循环,该循环可以神奇地实现任何实现的对象: 但是,仍然没有实现,这意味着要迭代一个,您必须执行以下操作: 有谁知道为什么仍然不执行? 编辑: 为澄清起见,我不是在谈论枚举的语言概念,而是在Java API中称为“ 枚举 ” 的Java特定类。 问题答案: 枚举没有被修改为支持Iterable,因为它是一个接口,而不是一个具体的类(例如Ve
本文向大家介绍迭代器 Iterator 是什么?相关面试题,主要包含被问及迭代器 Iterator 是什么?时的应答技巧和注意事项,需要的朋友参考一下 terator 接口提供遍历任何 Collection 的接口。我们可以从一个 Collection 中使用迭代器方法来获取迭代器实例。迭代器取代了 Java 集合框架中的 Enumeration,迭代器允许调用者在迭代过程中移除元素。