Дизайн и реализация класса матрицы

101
23 августа 2019, 11:00

Заранее извеняюсь, если вопрос вам заставит долго читать, но так как вопросов не очень много, решил позволить себя...

Реализован класс:

class Matrix {
    using  Rep =  std::valarray<double>;
    using S = std::slice;
public:
    Matrix(const size_t, const size_t);
    Matrix  subMatrix(const size_t,  const size_t, 
                      const size_t);
    template < class Cont >
    Matrix& assign(const Cont&,  size_t,  size_t);
    Rep& get_rep()   { return *pv; }
    const size_t size() const { return pv->size(); }        
    Rep row(size_t index) const;
    Rep column(size_t index) const;
    //...
private:
    size_t x, y;
    std::shared_ptr<Rep> pv;
    friend std::ostream& operator <<(std::ostream& os, const Matrix& m)
    {
        for (double d : *m.pv) {
            static size_t k = 0;
            if(k && !(k % m.y)) os << std::endl;
            ++k;
            os << std::fixed << std::setprecision(2)
               << std::setw(8)   << std::left  << d;
        }
        return os;
    }
};
Matrix::Matrix(const size_t row, const size_t column)
    : x(row), y(column), pv(new Rep(x * y)) {}
Matrix
Matrix::subMatrix(const size_t row,  const size_t column, const 
size_t start)
{  
    if ((start + row * column) > size())
       throw " out of range ";
    Matrix m(row, column);
    Rep& v = *pv;
    *m.pv = v[std::gslice(start, {row, column}, {y, 1})];
    return m;
}
Matrix&
Matrix::assign(const Cont &list,   size_t w,  size_t h)
{
    if (w && h) {
        const size_t sz = std::distance(std::begin(list), std::end(list));
        size_t n = w * h;
        while (n > sz && w > 1)    n = (--w) * h;
        if (n > sz) n = sz;
        *this = Matrix(w, h);
        std::copy_n(std::begin(list), n, std::begin(*pv));
    }
    return *this;
}
Matrix::Rep
Matrix::row(size_t row) const
{ row %= x; return Rep((*pv)[S(row * y, y, 1)]); }
Matrix::Rep
tvm::Matrix::column(size_t column) const
{ column %= y; return Rep((*pv)[S(column, x, y)]); }

Обеспечены некоторые необходимые функциональности. Теперь я могу написать программу:

Matrix m(5, 6);
// матрица как std::valarray
std::valarray<double>& v = m.get_rep();
// инициализируем значениями [1, 30]
std::iota(begin(v), end(v), 1);
// вычитаем 0.05 со всех элементов
v -= 0.05;
//min и max  значения
std::cout << "min_element: " << v.min() << std::endl
          << "max_element: " << v.max() << std::endl;
//составляем новую матрицу из первых двух строк 
//по 3 элемнета каждой строки, следующие 3 для второй матрицы    
Matrix m1 = m.subMatrix(2, 3, 0),
        m2 = m.subMatrix(2, 3, 3); //вторая половина
std::cout << m << std::endl  << std::endl << m1 << std::endl << m2;
// ну и т.д. и т.п.
Вывод:
min_element: 0.95
max_element: 29.95
0.95    1.95    2.95    3.95    4.95    5.95
6.95    7.95    8.95    9.95    10.95   11.95
12.95   13.95   14.95   15.95   16.95   17.95
18.95   19.95   20.95   21.95   22.95   23.95
24.95   25.95   26.95   27.95   28.95   29.95

0.95    1.95    2.95
6.95    7.95    8.95
3.95    4.95    5.95
9.95    10.95   11.95

В последних операциях, матрицы копируются. Первый вопрос по этому поводу.Насколько я понимаю умные указатели std::shared_ptr при копировании оба указателья будут ссылаться на обьект копируемого, ресурс под другой обьект освободится. Учитывая этот факт я выбрал именно этот указатель, чтобы все копировалось по умолчанию и корректно. Так вот:

  1. Действительно это будет работать корректно, или я что то путаю?

Как видно из программы, я получаю ссыльку на преставление матрицы и пользуясь эффективными и удобными методами std::valarray, могу выполнить различные действия над матрицей, легко и эффективно. По этому поводу второй вопрос:

  1. Стоит ли добавлять функциональности в матрицу, и если стоит, то какие? Или если стоит, то стоит ли делать это в производном классе, дабы избежать разбуханию интерфейса?

Старался быть немногословным(наверное не очень получилось)

READ ALSO
Как работает оператор (). С++

Как работает оператор (). С++

Например у меня есть функция int foo() {return 0;};И где нибудь в main я буду вызывать foo() , а как оператор () работает в данном случае ?

144
Библиотека C++ для быстрого рисования SVG

Библиотека C++ для быстрого рисования SVG

Какая библиотека на C++ существует для рисования SVG? Использовать буду в Qt, а встроенный отрисовщик в Qt не очень шустрый

124
Избыточность оператора delete[] в С++

Избыточность оператора delete[] в С++

Тут я как всегда не вовремя задумался вот над каким вопросомПри выделении памяти из кучи очевидно, что в куче должна сохраняться информация...

102