Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/126.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么微软Visual C++;图书馆实施';展开&x27;迭代器?_C++_Visual C++_Stl - Fatal编程技术网

C++ 为什么微软Visual C++;图书馆实施';展开&x27;迭代器?

C++ 为什么微软Visual C++;图书馆实施';展开&x27;迭代器?,c++,visual-c++,stl,C++,Visual C++,Stl,自始至终,几乎所有的迭代器在使用之前都是展开的 例如,如下所示: 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_unwr

自始至终,几乎所有的迭代器在使用之前都是展开的

例如,如下所示:

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; }
_Myptr是在迭代器本身中定义的,只是一个原始指针:

template <class _Ptr>
class unchecked_array_iterator {
...
private:
    _Ptr _Myptr; // underlying pointer
}
模板
类未检查\u数组\u迭代器{
...
私人:
_Ptr _Myptr;//底层指针
}

为什么VC++包装迭代器?

这是一种设计选择。实际上,对于类似数组的类型,如
std::array
std::vector
,迭代器可以是一个简单的
typedef
T*
,这很好地满足了迭代器语义,并且确实是GNU stdlibc++实现它的方式。但是从标准的角度来看,
迭代器是一个类似指针的对象,但不一定是指针。所以

  • 假设它是指针将是一个错误,并可能导致不可移植代码()
  • 包装迭代器允许迭代器调试(请参阅)。例如,这里有一个调试
    操作符+++

    _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;
    }
    
    \u CONSTEXPR17\u数组\u const\u迭代器和运算符++(){
    _STL_VERIFY(_Ptr,“无法增量值初始化数组迭代器”);
    _STL_VERIFY(_Idx<_Size,“无法增加数组迭代器的结束”);
    ++_Idx;
    归还*这个;
    }
    
  • 为什么VC++要展开迭代器?

  • 这是对错误报告的优化。在循环<>代码> STD::FuyAuth/<代码>中,而不是在<代码>中的范围内获得范围错误<每一个< /代码>,输入“<代码> >每个<<代码> >

  • 时,该错误被发出信号。
  • 这是一个性能优化

    • 在调试模式下,检查先决条件会导致更快的代码(调试模式已经慢了10多倍,所以即使在调试模式下,性能仍然很重要)
    • 在发布模式下,编译器可以优化指针访问,而不是每次通过迭代器推断指针访问。是的,在大多数情况下它仍然可以推断,但是额外的间接级别可能会导致代码中其他地方的内联决策不同

  • 如果我理解正确,这是一个调试功能

    包装的迭代器包含其他信息,这些信息允许实现验证各种前提条件,例如两个迭代器是否构成有效范围、迭代器是否未失效、迭代器仅与它所引用的元素的容器一起使用。
    \u Adl\u verify\u range
    就是这样一种检查

    但是,当在算法中实际使用迭代器时,实现不希望产生验证的开销(这将发生在每个
    ++
    操作中)。它将迭代器展开为不具有安全功能的版本。通常这意味着,未包装的版本只是一个指针(不一定是裸的,但包装在类中)


    在发布版本中,算法本身可以很好地优化,因为只涉及非常简单的类型,并且没有检查,但是初始安全检查可以保留,也可以省略,正如开发人员所希望的那样。

    什么是
    \u Unwrapped()
    ?我猜MS迭代器有一些与调试相关的包装。这不会带来开销吗?我看到了
    constexpr
    ,那么您指的是什么开销呢?@PaulMcKenzie后一个版本不是constexpr,如果它不可用的话。即使使用constexpr,它也会有更多的编译时间。也许我应该更加小心我的措辞。我已经更新了这个问题,我主要感兴趣的是它为什么会这样做。@IgorR。我放弃了这个,因为它有点像兔子洞,我没有足够的经验来解释清楚。但是是的,这是内置在迭代器中的,它似乎只是调用_unfuncy(),它返回适当的指针。@rustyx我已经包含了它。如果是这样的话,他们一开始就费心制作迭代器包装器似乎有些奇怪。GCC只是使用T*作为stl数组的迭代器,而Visual++有一个自定义数组迭代器类。显然,他们构建了这个迭代器包装器,然后在每个要使用的函数中打开它。看起来很奇怪-当然,除非我错过了它确实有用的所有情况。在调试构建中,迭代器进行范围检查。如果迭代器是一个typedef的指针,那就不好了,这可能会导致不可移植的代码。因此,展开是对用户隐藏的实现细节。
    template <class _Ptr>
    class unchecked_array_iterator {
    ...
    private:
        _Ptr _Myptr; // underlying pointer
    }
    
    _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;
    }