[英]Why does theMicrosoft Visual C++ library implementation 'unwrap' iterators?
在整个微软的 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 检查first <= last
,我理解,但我不太明白 _Get_unwrapped() 的目的:
#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();
}
似乎它想要衰减迭代器,或者将其转换为右值引用。
所以我的问题是为什么 Visual++ 使用这个范例? 据我所知,GCC 并没有这样做。
编辑
根据要求, iterator._Unwrapped()的来源
_NODISCARD constexpr _Ptr _Unwrapped() const noexcept {
return _Myptr;
}
_Myptr 在迭代器本身中定义,只是一个原始指针:
template <class _Ptr>
class unchecked_array_iterator {
...
private:
_Ptr _Myptr; // underlying pointer
}
为什么 VC++ 包装迭代器?
这是一个设计选择。 实际上,对于像std::array
和std::vector
这样的类数组类型,迭代器可以是T*
的简单typedef
,它很好地满足了迭代器语义,这就是 GNU stdlibc++ 实现它的方式。 但是从标准的角度来看, iterator
是一个类似指针的object,但不一定是指针。 所以...
包装迭代器允许迭代器调试(参见_ITERATOR_DEBUG_LEVEL
)。 例如,这是一个调试operator++
:
_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++ 解包迭代器?
这是对错误报告的优化。 在像std::for_each
这样的循环中,不是在for_each
for_each
发出错误信号。
这是一个性能优化。
如果我理解正确,这是一个调试功能。
包装的迭代器包含允许实现验证各种先决条件的附加信息,例如两个迭代器是否形成有效范围,迭代器尚未失效,迭代器仅与它所引用的元素的容器一起使用。 _Adl_verify_range
就是这样一种检查。
但是,当在算法中实际使用迭代器时,实现不希望产生验证开销(每个++
操作都会发生这种情况)。 它将迭代器解包到不具有安全功能的版本。 通常这意味着,未包装的版本只是一个指针(不一定是裸指针,而是包装在一个类中)。
在 Release 构建中,算法本身可以得到很好的优化,因为只涉及非常简单的类型并且没有检查,但是初始的安全检查可以保留或可以省略,如开发人员希望的那样。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.