g ++ 4.7.1中的奇怪迭代器行为

时间:2012-11-21 01:40:51

标签: c++ c++11 g++

我最初在Microsoft VS 2012中编写了一些使用std::array的代码。但是,在将其移植到g ++ 4.7.1时,出现了一些问题。它被缩小到平台之间迭代器行为的差异。

以下是隔离差异的基本代码示例:

#include <vector>
#include <array>
#include <iostream>

const std::array<std::array<int, 3>, 3> scoring_segment_codes_ = {{
    {{1, 2, 0}}, {{3, 4, 0}}, {{99, 100, 0}}
}};

int main()
{
    // This works on: g++ (Debian 4.5.3-9) 4.5.3
    // and Visual Studio 2012 (Windows 8)
    // but NOT g++ (Debian 4.7.1-7) 4.7.1
    for (auto i = scoring_segment_codes_.at(1).begin(); *i != 0; ++i)
    {
        std::cout << "Bad: " << *i << std::endl;
    } 

    std::cout << std::endl;

    // works on all three
    for (unsigned i = 0; i < scoring_segment_codes_.at(1).size(); i++) {
        std::cout << "Good: " << scoring_segment_codes_.at(1)[i] << std::endl;
    }

    std::cout << std::endl;

    // works on all three
    auto bees = scoring_segment_codes_.at(1);
    for (auto i = bees.begin(); *i != 0; ++i)
    {
        std::cout << "Good: " << *i << std::endl;
    }
    return 0;
}

此示例在g++ (Debian 4.5.3-9) 4.5.3Microsoft VC++上的输出为:

Bad: 3
Bad: 4

Good: 3
Good: 4
Good: 0

Good: 3
Good: 4

这就是我期望输出的结果。但是,g++ (Debian 4.7.1-7) 4.7.1会产生输出:

Bad: 3
Bad: 32513
Bad: 6297664

Good: 3
Good: 4
Good: 0

Good: 3
Good: 4

差异似乎是检索迭代器的方式。我原以为auto i = scoring_segment_codes_.at(1).begin()的结果是定义的行为。不是吗?或问题完全是另一回事?

如果这是g ++ 4.7.1的一个问题,不幸的是这是一个我坚持的系统。有什么我可以在g ++ 4.7.1上使用它吗?我知道通过并确保所有迭代器使用兼容是一个选项,但这似乎是一个非常丰富的错误来源。

1 个答案:

答案 0 :(得分:2)

根据我的评论,我使用的g ++版本略有不同(4.7.0)。查看其数组实现的实际代码可以得到:

#ifdef __EXCEPTIONS
  constexpr const_reference
  at(size_type __n) const
  {
return __n < _Nm ? 
       _M_instance[__n] : throw out_of_range(__N("array::at"));
  }
//#else path

Constexpr GCC Wiki,我们得到了#34;即使它涉及对未被声明为noexcept的constexpr函数的调用,常量表达式也是noexcept。&#34;。因此看起来有人错误地将其标记为constexpr,即使它可以抛出。

我不确定这是否与错误报告相关,但它确实看起来像一个错误。临时解决方法是使用operator[] - 但这看起来operator[]的工作原因和at没有。

编辑:要回答评论,修改标准库标题是一种可能性,尽管肯定存在问题。

另一个可能是创建一个如下所示的包装器(注意我还没有对此进行测试):

template <typename T, std::size_t sz>
const T& at(const std::array<T, sz>& arr, typename std::array<T, sz>::size_type index)
{
    if(index < arr.size())
        return arr[index];
    throw std::out_of_range("array::at");
}

同样适用于非const参考版本。请注意,这可以直接调用array.at(),因为at()的非常量版本是正确的。

这些解决方案都不是完美的,但它们至少可以帮助您解决这个问题。

第二次编辑:更多地看一下,显然我错了,宣布使用三元运算符的constexpr函数是合法的。我会把修复程序保留在这里,因为它有效,但我对正在发生的事情的分析是不正确的。