当前位置: 首页 > 知识库问答 >
问题:

为什么微软Visual C库实现“展开”迭代器?

吉凯捷
2023-03-14

在整个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
}

共有2个答案

甘君之
2023-03-14
匿名用户

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

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

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

在Release版本中,算法本身可以得到很好的优化,因为只涉及非常简单的类型,没有检查,但初始安全检查可以保留或可以省略,如开发人员所愿。

孟文栋
2023-03-14

为什么VC包装迭代器?

这是一种设计选择。实际上,对于类似数组的类型,比如std::arraystd::vector,迭代器可以是一个简单的typedefT*,这很好地满足了迭代器语义,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的迭代器。 这个选择背后的理性是什么? 与相比,用例的优势是什么?

    • 问题内容: 在Java 5及更高版本中,您具有foreach循环,该循环可以神奇地实现任何实现的对象: 但是,仍然没有实现,这意味着要迭代一个,您必须执行以下操作: 有谁知道为什么仍然不执行? 编辑: 为澄清起见,我不是在谈论枚举的语言概念,而是在Java API中称为“ 枚举 ” 的Java特定类。 问题答案: 枚举没有被修改为支持Iterable,因为它是一个接口,而不是一个具体的类(例如Ve

    • 本文向大家介绍迭代器 Iterator 是什么?相关面试题,主要包含被问及迭代器 Iterator 是什么?时的应答技巧和注意事项,需要的朋友参考一下 terator 接口提供遍历任何 Collection 的接口。我们可以从一个 Collection 中使用迭代器方法来获取迭代器实例。迭代器取代了 Java 集合框架中的 Enumeration,迭代器允许调用者在迭代过程中移除元素。

    • 问题内容: 为什么接口不扩展? 该方法可以简单地返回。 是故意的还是对Java设计师的监督? 能够将循环与这样的迭代器一起使用将很方便: 其中返回迭代器。 问题答案: 因为迭代器通常指向集合中的单个实例。Iterable意味着可以从一个对象获得迭代器以遍历其元素-无需迭代单个实例(迭代器代表的是该实例)。