3

我最初编写了一些std::array在 Microsoft VS 2012 中使用的代码。但是,将其移植到 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.3and上的输出Microsoft 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 上工作的吗?我知道通过并确保所有迭代器的使用是兼容的是一种选择,但这似乎是一个非常丰富的错误来源。

4

1 回答 1

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

Consexpr GCC Wiki中,我们得到“常量表达式是 noexcept,即使它涉及对未声明为 noexcept 的 constexpr 函数的调用。”。因此看起来有人错误地将其标记为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");
}

对于非常量参考版本也是如此。请注意,这可以array.at()直接调用,因为非常量版本at()是正确的。

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

第二次编辑:仔细研究一下,显然我错了,声明constexpr使用三元运算符抛出的函数是合法的。我将把修复留在这里,因为它有效,但我对正在发生的事情的分析是不正确的。

于 2012-11-21T02:59:27.967 回答