[英]Why does theMicrosoft Visual C++ library implementation 'unwrap' iterators?
Throughout microsofts stl implementation , pretty much all of their iterators are unwrapped before they are used.在整个微软的 stl 实现中,几乎所有的迭代器在使用之前都被解包。
For instance, for_each looks like this:例如, 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 checks that first <= last
, which I understand, but I dont quite understand the purpose of _Get_unwrapped(): _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();
}
It seems that it wants to decay the iterator, or cast it to an rvalue reference.似乎它想要衰减迭代器,或者将其转换为右值引用。
So my question is why does Visual++ use this paradigm?所以我的问题是为什么 Visual++ 使用这个范例? GCC does not do this as far as I can tell.据我所知,GCC 并没有这样做。
EDIT编辑
As requested, source of iterator._Unwrapped()根据要求, iterator._Unwrapped()的来源
_NODISCARD constexpr _Ptr _Unwrapped() const noexcept {
return _Myptr;
}
_Myptr is defined in the iterator itself, and is just a raw pointer: _Myptr 在迭代器本身中定义,只是一个原始指针:
template <class _Ptr>
class unchecked_array_iterator {
...
private:
_Ptr _Myptr; // underlying pointer
}
Why does VC++ wrap iterators?为什么 VC++ 包装迭代器?
It's a design choice.这是一个设计选择。 Indeed, for array-like types like std::array
and std::vector
an iterator can be a simple typedef
to T*
, which satisfies iterator semantics nicely, and indeed this is how GNU stdlibc++ implements it.实际上,对于像std::array
和std::vector
这样的类数组类型,迭代器可以是T*
的简单typedef
,它很好地满足了迭代器语义,这就是 GNU stdlibc++ 实现它的方式。 But from the standard perspective, iterator
is a pointer-like object, but isn't necessarily a pointer.但是从标准的角度来看, iterator
是一个类似指针的object,但不一定是指针。 So...所以...
Wrapping iterators allows for iterator debugging (see _ITERATOR_DEBUG_LEVEL
).包装迭代器允许迭代器调试(参见_ITERATOR_DEBUG_LEVEL
)。 For example here's a debug operator++
:例如,这是一个调试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; }
Why does VC++ unwrap iterators?为什么 VC++ 解包迭代器?
It's an optimization of error reporting.这是对错误报告的优化。 In loops like std::for_each
, instead of getting a range error in the middle of for_each
, the error is signaled upon entry into for_each
.在像std::for_each
这样的循环中,不是在for_each
for_each
发出错误信号。
It's a performance optimization.这是一个性能优化。
If I understand correctly, this is a debugging feature.如果我理解正确,这是一个调试功能。
The wrapped iterators contain additional information that allows the implementation to verify various preconditions, such as whether two iterators form a valid range, that an iterator has not been invalidated, that an iterator is used only with a container to whose element it refers.包装的迭代器包含允许实现验证各种先决条件的附加信息,例如两个迭代器是否形成有效范围,迭代器尚未失效,迭代器仅与它所引用的元素的容器一起使用。 _Adl_verify_range
is one such check. _Adl_verify_range
就是这样一种检查。
But then, when the iterator is actually used in the algorithm, the implementation does not want to incur the overhead of the verifications (which would happen for each ++
operation).但是,当在算法中实际使用迭代器时,实现不希望产生验证开销(每个++
操作都会发生这种情况)。 It unwraps the iterator to a version that does not have the safety features.它将迭代器解包到不具有安全功能的版本。 Usually this means, that the unwrapped version is just a pointer (not necessarily a naked one, but wrapped in a class).通常这意味着,未包装的版本只是一个指针(不一定是裸指针,而是包装在一个类中)。
In Release builds, the algorithm itself can be optimized well because only very simple types are involved and no checks, but the initial safety checks can remain or can be omitted, as the developer wishes.在 Release 构建中,算法本身可以得到很好的优化,因为只涉及非常简单的类型并且没有检查,但是初始的安全检查可以保留或可以省略,如开发人员希望的那样。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.