提升any_range性能:std :: prev(iterator)与--iterator

时间:2012-07-01 10:43:42

标签: c++ performance boost c++11 iterator

我最近开始更喜欢自由函数std::nextstd::prev来显式复制和递增/递减迭代器。现在,我在一个非常具体的案例中看到了奇怪的行为,我很感激任何帮助揭开它的神秘面纱。

我有一个插值/外推函数在某boost::any_range的{​​{1}}上运行。范围类型的完整定义是:

X_type

在此特定情况下,boost::any_range < const X_type, boost::random_access_traversal_tag, const X_type, std::ptrdiff_t > 是从any_range分配的,其中包含指向iterator_range的两个指针,该const X_type用作X_type视图的大约一半{ {1}} data()的区域。

在MSVC 2010中编译我的应用程序,一切正常。 在MinGW g ++ 4.7.0中编译相同的代码,它似乎挂在一个特定的位置,然后我缩小到这个(稍微缩写):

vector<char>

单步执行gdb中的代码,我发现它没有被卡住,只需要花费很长时间从单// Previously ensured conditions: // 1) xrange is nonempty; // 2) yrange is the same size as xrange. auto x_equal_or_greater = std::lower_bound(std::begin(xrange),std::end(xrange),xval); if (x_equal_or_greater == std::end(xrange)) { return *yit_from_xit(std::prev(x_equal_or_greater),xrange,yrange); } 次调用返回 - 这在libstdc ++中以{{1}的方式实现}最终是std::prev运算符。

仅将std::advance行替换为:

+=

表现再次出色,几乎没有延迟。

我知道使用类型擦除迭代器(return的那些)的开销,但即便如此,上面两种情况真的应该承担这样不同的成本吗?或者我做错了什么?

1 个答案:

答案 0 :(得分:3)

好的,在回复SplinterOfChaos's comment后,我意识到了什么。问题出在你使用any_range上。特别是,第三个参数,表示Reference参数是const int。在boost迭代器外观中,当引用不是真正的引用时,它将使用std::input_iterator_tag,或者不提供STL等效标记。

这与事实有关,严格来说,所有前向,双向和随机访问STL迭代器必须使用真实引用作为其引用类型。从C ++ 11标准的24.2.5开始:

如果

,类或内置类型X满足前向迭代器的要求 - X满足输入迭代器(24.2.3),

的要求 - X满足DefaultConstructible要求(17.6.3.1),

- 如果X是可变迭代器,则引用是对T的引用;如果X是常量迭代器,则引用是对const T

的引用 - 表109中的表达式是有效的,并具有指示的语义,

- X型对象提供多次通过保证,如下所述。

在这种情况下,当查询std::input_iterator_tag时,它会返回iterator_category,这会导致调用std::prev()转入未定义的行为

无论哪种方式,解决方案是将boost::any_range的使用更改(如果可能)到以下内容:

  boost::any_range <
        const X_type,
        boost::random_access_traversal_tag,
        const X_type&,
        std::ptrdiff_t
    >

这将使其iterator_category std::random_access_iterator_tag,并按原先的预期执行操作。