0

SafeC++に関する本を読んでいます。ここで、著者は、範囲外の配列読み取りを回避する方法について言及しました。ここでは、多次元配列の範囲外の配列読み取りを回避する方法について説明します。ここでは、作者はoperator()代わりに次のリンクに示す機能を使用しoperator[]、次の説明をしました。

https://github.com/vladimir-kushnir/SafeCPlusPlus/blob/master/scpp_matrix.hpp

ここで、多次元配列にアクセスするには[]、matrix [i] [j]などの複数の演算子、または()matrix(i、j)などの単一の演算子を使用する必要があることに注意してください。

最初のアプローチは、演算子がi番目の行の0番目の要素へ[]のポインターを返すようにした場合に実現できます。T*ただし、これにより、列インデックスが範囲外であるとの診断が拒否され、実行時にバグをキャッチするという目的が無効になります。もちろん、行へのスマート参照を含むテンプレートクラスを作成し、最初の演算子([i])を使用するインスタンスを返し、2番目の演算子()で境界チェックを使用することもできます[j]

私の質問は、「行へのスマート参照を含むテンプレートクラスを作成し、最初の演算子()を使用するインスタンスを返し、次に2番目の演算子( )[i]で境界チェックを使用する[j]」とはどういう意味ですか。?上記のロジックをC++で実装する方法のサンプルコードを提供するように要求しますか?

お手数をおかけしますが、よろしくお願いいたします。

4

1 に答える 1

4

基本的な考え方は次のようになります。

#include <vector>
#include <iostream>

template <class T>
class matrix { 
    size_t cols;
    size_t rows;
    std::vector<T> data;

    class row_proxy {  // This class is the part the question really asked about
        size_t row;
        matrix &m;
    public:
        row_proxy(matrix &m, size_t row) : row(row), m(m) {}

        T &operator[](size_t col) {
            if (row >= m.rows || col >= m.cols) // Note: row & col are indices not array count
                throw std::logic_error("Bad index");
            return m.data[row * m.cols + col];
        }
    };

public:

    matrix(size_t cols, size_t rows) : rows(rows), cols(cols), data(rows*cols) {}

    row_proxy operator[](size_t row) { 
        return row_proxy(*this, row);
    }
};

int main() { 
    matrix<int> m(3, 3);

    for (int i=0; i<3; i++)   // fill the matrix with identifiable numbers
        for (int j=0; j<3; j++)
            m[i][j] = i * 100 + j;

    for (int i=0; i<3; i++) { // show the content
        for (int j=0; j<3; j++)
            std::cout << m[i][j] << "\t";
        std::cout << "\n";
    }

    try {                     // test the bounds checking.
        m[4][1] = 21;
    }
    catch(std::logic_error &e) { 
        std::cerr << e.what(); 
    }

    return 0;
}

したがって、行列を作成するときは、そのサイズをrowsとに保存しcolsます。マトリックスで使用する場合operator[]、マトリックス内のアイテムへの参照を直接返そうとはしません。むしろ、行とマトリックスを追跡operator[]その自分の。

したがって、を使用すると、最初のものはプロキシオブジェクトにmatrix[a][b]保存aされます。matrix次に、[b]パーツはそのプロキシオブジェクトで呼び出されます。aこれにより、との両方bが行列用に保存した範囲内にあることが確認され、その場合は、ベクトル内の正しいオブジェクトへの参照が返されます。std::Logic_errorそれ以外の場合は、 (最良の選択ではない可能性があります-私が最初に発生したものだけです)をスローします。

この一般的な考え方にはかなりのバリエーションがあることを付け加えておきます。ほんの一例として、コンパイル時に配列のサイズを指定できますが、サイズをテンプレートパラメータとして渡します。matrix<int, 2, 3>これにはいくつかの利点があります。たとえば、matrix<int, 3, 2>まったく異なるタイプであるため、誤って一方を他方に割り当てることはできません。また、いくつかの欠点もあります(最も明らかなのは、コンパイル時にサイズを知る必要があります。そうしないと、まったく機能しません)。

于 2013-03-14T05:53:34.940 に答える