3

私は元々、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で動作させることができるものはありますか?すべてのイテレータの使用法に互換性があることを確認することはオプションですが、これは非常に豊富なバグの原因のようです。

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

Constexpr GCC Wikiから、「定数式は、noexceptとして宣言されていないconstexpr関数の呼び出しを含む場合でもnoexceptです」ということがわかります。constexprしたがって、投げることができるとしても、誰かが誤ってラベルを付けたように見えます。

これがバグレポートとして関連しているかどうかはわかりませんが、確かにバグのように見えます。一時的な修正は使用することですが、これは理由が機能しoperator[]ているように見えますが、機能していません。operator[]at

編集:コメントに答えるために、標準ライブラリヘッダーを変更することは1つの可能性ですが、それは確かに問題があります。

もう1つは、おそらく次のようなラッパーを作成することです(これはテストしていないことに注意してください)。

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()が正しいため、これは直接呼び出すことができることに注意してください。

これらの解決策はどちらも完璧ではありませんが、少なくともこのバグを回避するのに役立つ可能性があります。

2番目の編集:もっと調べてみると、明らかに私は間違っていconstexprます。三項演算子を使用してスローする関数を宣言することは合法です。修正は機能するのでここに残しておきますが、何が起こっているのかについての私の分析は正しくありません。

于 2012-11-21T02:59:27.967 に答える