2015-12-28 6 views
6

私はmat [3] [3]と呼ばれるクラスのプライベートメンバーを持っています。クラス外でこの3x3配列にアクセスできます変更しないでください)。私の配列にポインタを返すアクセサメソッドを書くことは可能ですか?これどうやってするの?コードサンプルを提供してください。ここで2D配列(privateメンバー)のアクセサーを書く方法

が私のクラスである:

class myClass { 
private: 
    int mat[3][3]; 
public: 
    return_value get_mat(void); 
}; 

私は、アレイ内の一つ一つを、すべてのint型へのアクセスに

int get_mat(int i, int j); 

のようなものを使用することができます知っているが、呼び出すことは非効率的ではありません配列のすべてのメンバーのアクセサーですか?

+0

'int i、int j'バージョンは非効率的ではありません。コンパイラはこの種のことをうまく処理します。 –

答えて

9

私の配列にポインタを返すアクセサメソッドを書くことは可能ですか?これどうやってするの?

は、ここに1つの方法です:

#include <iostream> 
#include <algorithm> 
#include <iterator> 

class myClass { 
public: 

    const int* operator[](size_t i) const { 
     return mat[i]; 
    } 

    int* operator[](size_t i) { 
     return mat[i]; 
    } 

    int* get_mat() { 
     return &mat[0][0]; 
    } 

    const int* get_mat() const { 
     return &mat[0][0]; 
    } 

private: 
    int mat[3][3]; 
}; 

int main() 
{ 
    using namespace std; 

    myClass m; 
    m[0][1] = 6; 
    cout << m[0][1] << endl; 

    fill(m.get_mat(), m.get_mat() + 9, 11); 
    copy(m.get_mat(), m.get_mat() + 9, ostream_iterator<int>(cout, ", ")); 
    cout << endl; 

    return 0; 
} 

が、配列のすべてのメンバーのためのアクセサを呼び出すことは非効率的ではないでしょうか?

幸いにも、リリースビルドでは、あなたのコンパイラはおそらくあなたが想像するよりもはるかに優れたものをすべて最適化します。

あなたの意図をエレガントに表現します。コンパイラがあなたに最適なコードを書くことを許可します。

予想される出力:

6 
11, 11, 11, 11, 11, 11, 11, 11, 11, 

我々は行列クラスを肉付けし始めとして、我々は、おそらく(このコードはおそらく、C++ 14が必要)のバッファオーバーランに対するいくつかの安全対策に構築を開始したいと思います。 ..

#include <iostream> 
#include <algorithm> 
#include <iterator> 
#include <functional> 
#include <random> 
#include <cassert> 

template<class T, size_t N> 
struct safe_array_ref 
{ 
    constexpr safe_array_ref(T* data) : _data(data) {} 

    constexpr T& operator[](size_t i) const noexcept { 
     assert(i < N); 
     return _data[i]; 
    } 

    constexpr T* begin() const { 
     return _data; 
    } 

    constexpr T* end() const { 
     return _data + N; 
    } 

    constexpr size_t size() const { 
     return N; 
    } 

private: 
    T* _data; 
}; 

class myClass { 
public: 

    auto operator[](size_t i) const { 
     // provide some degree of safety 
     assert(i < extent_1); 
     return safe_array_ref<const int, extent_2>(mat[i]); 
    } 

    auto operator[](size_t i) { 
     // provide some degree of safety 
     assert(i < extent_1); 
     return safe_array_ref<int, extent_2>(mat[i]); 
    } 

    int* get_mat() { 
     return &mat[0][0]; 
    } 

    const int* get_mat() const { 
     return &mat[0][0]; 
    } 

    const int* begin() const { 
     return get_mat(); 
    } 

    const int* end() const { 
     return get_mat() + total_extent; 
    } 

    int* begin() { 
     return get_mat(); 
    } 

    int* end() { 
     return get_mat() + total_extent; 
    } 

    constexpr size_t size() const { 
     return total_extent; 
    } 


private: 
    int mat[3][3]; 

public: 
    constexpr static size_t extent_1 = std::extent<decltype(mat)>::value; 
    constexpr static size_t extent_2 = std::extent<std::remove_extent_t<decltype(mat)>>::value; 
    constexpr static size_t total_extent = extent_1 * extent_2; 
}; 

int main() 
{ 
    using namespace std; 

    myClass m; 
    m[0][1] = 6; 
    cout << m[0][1] << endl; 

    generate(m.begin(), 
      m.end(), 
      bind(uniform_int_distribution<int>(0,99), 
        default_random_engine(random_device()()))); 

    // copy the whole matrix to stdout 
    copy(m.begin(), 
     m.end(), 
     ostream_iterator<int>(cout, ", ")); 
    cout << endl; 

    // copy one row/column of the matrix to stdout   
    copy(m[1].begin(), 
     m[1].end(), 
     ostream_iterator<int>(cout, ", ")); 
    cout << endl; 


    return 0; 
} 

サンプル出力:

6 
76, 6, 39, 68, 40, 77, 28, 28, 76, 
68, 40, 77, 
+0

'std :: vector'と同様に、' M [i] [j] 'の範囲チェックと' M.at(i、j) 'の文法の範囲チェックを許可する方が良いと思います。多くの場合、範囲チェックは安全に省略することができます。また、適切なC++行列は 'assert()'を使用する代わりに 'std :: out_of_range'を投げるべきです - 範囲外のエラーは行列クラスの内部ではありません。 – Walter

+0

これは味の問題です。私は元のバージョンを好む。 (そして私はop [] /違いが間違いだと思う)。最後に、op []は "範囲チェックなし"ではありません - それは未定義の動作です。アサーションを打つことは、未定義の動作を実装するための完全に合理的な方法です。 (インラインであれば、オプティマイザはほとんどのレンジチェックを削除します) –

+0

@Walter NDEBUGセット(リリースビルド)でコンパイルすると、アサートはNOPにコンパイルされるため、本番では範囲チェックはされませんが、少なくともあなたにはチャンスがあります開発中のバグを発見する。私は '.at()'バージョンがrange_errorを投げるべきであることに絶対に同意します。 –

0

私の配列にポインタを返すアクセサメソッドを書くことは可能ですか?

あなたはtypedefを簡素化することができるあなたの内部配列

const int (&myClass::as_array())[3][3] const { return mat; } 

への参照を返すために、この醜い構文を使用することがあります。

using int3x3 = int [3][3]; 

const int3x3& myClass::as_array() const { return mat; } 

std::arrayはあまりにも良い選択肢です。

しかし、配列のすべてのメンバーに対してアクセサを呼び出すのは非効率ではありません。

int myClass::get_value(int i, int j) const { return mat[i][j]; }は完全に有効ですので、コンパイラによってインライン展開する必要があります。

アレイからそれぞれintにアクセスする必要がある場合は、ほとんどすべての代替が同じアセンブラコードになります。

このgetterのpitfallは、インデックスの代わりにイテレータで動作するstlのほとんどのアルゴリズムを使用できないということです。

の簡単な方法の1つは、[3][3]から[3*3]への配列の次元を変更することです(インデックス作成は手作業で行います)。