Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write accessor for 2D array (private member)

I have a private member of class called mat[3][3], and I want to be able to access this 3x3 array outside of my class (only read it, not change). Is it possible to write accessor method that returns pointer to my array? How can I do this? Please provide code sample.

Here is my class:

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

I know I can use something like

int get_mat(int i, int j);

to access every int inside the array one by one, but wouldn't it be inefficient to call the accessor for every member of the array?

like image 262
Firmus Avatar asked Dec 28 '15 15:12

Firmus


1 Answers

Is it possible to write accessor method that returns pointer to my array? How can I do this?

Here's one way:

#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;
}

but wouldn't it be inefficient to call the accessor for every member of the array?

Happily, no. in a release build your compiler will optimise all that away much better than you can probably imagine.

Express your intent elegantly. Allow the compiler to write optimal code for you (it will).

expected output:

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

As we start to flesh out the matrix class, we'd probably want to start building in some safety measures against buffer overruns (this code probably requires 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;
}

sample output:

6
76, 6, 39, 68, 40, 77, 28, 28, 76,
68, 40, 77,
like image 88
Richard Hodges Avatar answered Nov 08 '22 08:11

Richard Hodges