Home > database >  Slice and assign a matrix from a matrix class using a proxy class in C
Slice and assign a matrix from a matrix class using a proxy class in C

Time:01-18

I would like to have a simple matrix class with the feature of slicing to avoid nested for-loops. For that, I have written the following class

// matrix.hpp

#include <cstddef>
#include <iostream>
#include <vector>

template <typename T>
class SubMatrix;

template <typename T>
class Matrix
{
    std::vector<T> _matrix;
    size_t _rows;
    size_t _cols;

public:
    Matrix(const size_t rows, const size_t cols) : _matrix(rows * cols),
                                                   _rows(rows),
                                                   _cols(cols) {}

    Matrix(const size_t rows, const size_t cols, const T init)
        : _matrix(rows * cols, init),
          _rows(rows),
          _cols(cols) {}

    Matrix(Matrix &other) : _matrix(other._matrix),
                            _rows(other._rows),
                            _cols(other._cols) {}

    ~Matrix() {}

    Matrix &operator=(Matrix &other)
    {
        for (size_t i = 0; i < _matrix.size();   i)
            _matrix[i] = other._matrix[i];

        _rows = other.rows();
        _cols = other.cols();

        return *this;
    }

    T operator()(const size_t i, const size_t j) const
    {
        return _matrix.at(_cols * i   j);
    }

    T &operator()(const size_t i, const size_t j)
    {
        return _matrix.at(_cols * i   j);
    }

    /*
        i, j: initial row and column, respectively
        p: number of rows from i
        q: number of columns from j
    */

    void slice(const size_t i, const size_t j,
               const size_t p, const size_t q,
               Matrix &other)
    {
        size_t index{0};
        size_t cont{0};

        for (size_t ii = i; ii < i   p; ii  )
        {
            for (size_t jj = j; jj < j   q; jj  )
            {
                index = _cols * ii   jj;
                _matrix[index] = other._matrix[cont];

                  cont;
            }
        }
    }

    void print()
    {
        std::cout << '\n';
        for (size_t i = 0; i < _rows;   i)
        {
            for (size_t j = 0; j < _cols;   j)
                std::cout << this->operator()(i, j) << ' ';

            std::cout << '\n';
        }
    }

    SubMatrix<T> operator()(const size_t i,
                            const size_t j,
                            const size_t p,
                            const size_t q)
    {
        SubMatrix<T> sub_matrix(i, j, p, q, *this);
        return sub_matrix;
    }
};

To have the slicing feature as

A(i, j, p, q) = B

where A and B are matrices, i and j are the initial indices, and p and q are the number of lines from i and q the number of lines from j, I have written the following proxy class

template <typename T>
class SubMatrix
{
    size_t _i, _j, _p, _q;

public:
    Matrix<T> _matrix;

    SubMatrix(const size_t i,
              const size_t j,
              const size_t p,
              const size_t q,
              Matrix<T> &matrix) : _i(i),
                                   _j(j),
                                   _p(p),
                                   _q(q),
                                   _matrix(matrix) {}

    SubMatrix<T> &operator=(Matrix<T> &matrix)
    {
        _matrix.slice(_i, _j, _p, _q, matrix);
        return *this;
    }
};

The code ran smoothly, but the slicing is not being performed correctly. The matrix B is not assigned to A.

// main.cpp

#include "matrix.h"

int main()
{
    Matrix<double> A(5, 5, 1.0);
    Matrix<double> B(3, 3, 9.0);

    A.print();

    B.print();

    A(1, 1, 3, 3) = B;
    A.print();


    return 0;
}

The output of the code is:

1 1 1 1 1 
1 1 1 1 1 
1 1 1 1 1 
1 1 1 1 1 
1 1 1 1 1 

9 9 9 
9 9 9 
9 9 9 

1 1 1 1 1 
1 1 1 1 1 
1 1 1 1 1 
1 1 1 1 1 
1 1 1 1 1

Does anyone know why the values of B is not being assigned to A?

CodePudding user response:

SubMatrix<T> Matrix::operator() creates a temporary copy of its own internal _matrix member. Next this copy is modified by the assignment from B.

But the original A remains unchanged. When you use a reference instead, the assignment operator will assign to the original _matrix member:

template <typename T>
class SubMatrix
{
// ...
    Matrix<T> &_matrix;
public:
// ...
};

Unrelated, but _matrix should be a private member.

CodePudding user response:

What your code does is basically this:

#include <iostream>


struct Proxy { int x; };

struct twoNumbers { 
    int a = 0;
    int b = 0;
    Proxy aset() {return {a};}
    Proxy bset() {return {b};}
};

int main() {
    twoNumbers A;
    auto p = A.aset();
    p.x = 42;
    std::cout << A.a;
}

The Proxy stores a copy of the value and modifying that copy has no effect on the original value.

What you want is Proxy holding a reference that allows to modify the original. Something like this:

#include <iostream>


struct Proxy { int& x; };

struct twoNumbers { 
    int a = 0;
    int b = 0;
    Proxy aset() {return {a};}
    Proxy bset() {return {b};}
};

int main() {
    twoNumbers A;
    auto p = A.aset();
    p.x = 42;
    std::cout << A.a;
}

output:

42
  • Related