我最初在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.3
和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上使用它吗?我知道通过并确保所有迭代器使用兼容是一个选项,但这似乎是一个非常丰富的错误来源。
答案 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
函数是合法的。我会把修复程序保留在这里,因为它有效,但我对正在发生的事情的分析是不正确的。