0

I am trying to write a templated Matrix class that can be extended and used for other things like vectors. However, I cannot figure out why operator[] in the Row class, does not return the reference to the actual data_ vector in the Matrix, but a reference to a different data_.

The code below is the code for the Matrix. I'm using a Row class, which is hidden in a namespace so that I can use the double square brackets to access an element. In that class there is a shared pointer to the parent matrix, so that I can access the data_ vector in it from the Row class, which doesn't seem to work though.

#ifndef YAGE_MATH_MATRIX_HPP
#define YAGE_MATH_MATRIX_HPP

#include <iostream>
#include <memory>
#include <vector>

namespace yage
{

template<int Rows, int Cols, class Type> class Matrix;

namespace detail
{

template<int Rows, int Cols, class Type> class Row
{
private:
    std::shared_ptr<Matrix<Rows, Cols, Type>> parent_;
    int index_;

public:
    Row<Rows, Cols, Type>(std::shared_ptr<Matrix<Rows, Cols, Type>> parent, int index) :
        parent_(parent), index_(index)
    {}

    Type &operator[](int col)
    {
        std::cout<<"Other Data: "<<&parent_->data_[index_*Cols+col]<<'\n';
        return parent_->data_[index_*Cols+col];
    }
};

} // detail

template<int Rows=4, int Cols=4, class Type=double> class Matrix
{
    friend class detail::Row<Rows, Cols, Type>;
private:
    std::vector<Type> data_;

public:
    Matrix<Rows, Cols, Type>() : data_(Rows*Cols) {}
    Matrix<Rows, Cols, Type>(int rows, int cols) : data_(rows*cols) {}

    detail::Row<Rows, Cols, Type> operator[](int row)
    {
        std::cout<<"Main Data: "<<&data_[10]<<'\n';     
        return detail::Row<Rows, Cols, Type>(std::make_shared<Matrix<Rows, Cols, Type>>(*this), row);
    }
};

} // yage

#endif

I tested these classes with the following program

#include "Math/matrix.hpp"

#include <iostream>

int main()
{
    yage::Matrix<4, 4> matrix;

    matrix[2][2];
    return 1; 
}

and the output was

Main Data: 0x1f72960
Other Data: 0x1f72e30

which point to two different locations.

I know that there are different ways of solving this, for example using the operator(x, y) overload, but I am curious about what mistake I have made.

Thank you for your help.

  • `std::make_shared>(*this)` makes a new `Matrix` that is a copy of `this`. I'm not sure how to fix your architecture. Perhaps with [`std::enable_shared_from_this`](http://en.cppreference.com/w/cpp/memory/enable_shared_from_this)? If rows are wholly owned by `Matrix` objects, you could simply use raw non-owning pointers to refer to the row's parent matrix. – François Andrieux Jun 07 '17 at 15:25
  • What do you mean by `operator(x, y)`? Are you referring to [`operator()`](http://en.cppreference.com/w/cpp/language/operators#Function_call_operator)? – François Andrieux Jun 07 '17 at 15:27
  • I completely forgot that it created a new `Matrix`, thank you so much for the quick answer, I think that because of that I will just use a raw pointer to refer to the `this` pointer. – Yann Herklotz Jun 07 '17 at 15:28
  • and yes that is what I was refering to, with the x and y coordinate in the Matrix. – Yann Herklotz Jun 07 '17 at 15:29
  • @YannHerklotz Is there really any need to use raw pointers insted of references in your case? – Gasper Jun 07 '17 at 15:41
  • @Gasper What exactly do you mean by that? I would love not to have to use a raw pointer, but I can't see a way of doing it there. – Yann Herklotz Jun 07 '17 at 15:48
  • @YannHerklotz Try using `Matrix&` as a type for `parent_` and first type in `Row` ctor. Then pass `*this` to it, instead of `make_shared(...)`. [Example](https://ideone.com/oVJ7ef) – Gasper Jun 07 '17 at 15:56
  • @Gasper That wouldn't work though because it will still create a copy of the object in the initialization list, which is what i wanted to avoid by using shared_ptr and now a raw ptr. – Yann Herklotz Jun 07 '17 at 16:24
  • @YannHerklotz It would not create a copy, it would create a [reference](https://en.wikipedia.org/wiki/Reference_(C%2B%2B)) to the same `Matrix` instance. If it would have created a copy it would not return the same memory address. See, for example, [this](https://stackoverflow.com/questions/57483/what-are-the-differences-between-a-pointer-variable-and-a-reference-variable-in) – Gasper Jun 07 '17 at 16:32
  • @Gasper Thank you so much this works nicely! I had misunderstood your answer and interpretted it wrong, forgot that a reference can be stored and is therefore not copied. – Yann Herklotz Jun 07 '17 at 16:44

0 Answers0