0

I wish to pass by reference my data to a class where the reference itself should be the public variable, to be accessed by member functions. If I declare my class and its constructor

class max_likelihood { 
public: 
MatrixXd dat
max_likelihood(const Ref<const MatrixXd>& dat_in)
{dat = dat_in;}

I get functioning code but end up creating a copy of dat, which I would like to avoid.

I have tried to do instead:

class max_likelihood {
public:
const Ref<const MatrixXd>& dat;
max_likelihood(const Ref<const MatrixXd>& dat){}

But this does not work and/or won't let me access the reference to dat and does not even compile.

Based on my research I have found this bit from this question

if you want to reassign a Ref to reference another buffer, then use a placement new to re-call the constructor of Ref. Don't forget to call the destructor first.

I believe this may help answer my question but I do not know what these instructions would mean in practice, hence my question here. Specifically, I suppose I am creating a new instance of a Ref object to pass around the passed reference. How can I interpret the answer to this or find a more elegant way to use Ref objects within classes when the source data is created elsewhere, say read in from a file via main?

halfer
  • 19,824
  • 17
  • 99
  • 186
Hirek
  • 435
  • 3
  • 12

4 Answers4

2

I get functioning code but end up creating a copy of dat, which I would like to avoid.

Using reference to avoid data copy in this case is a terrible idea, maintaining reference in a class makes things quite complicated. So if MatrixXd properly designed for C++11 or later just use move semantics:

class max_likelihood { 
public: 
   MatrixXd dat;
   max_likelihood(MatrixXd dat_in) : dat( std::move(dat_in) ) {}
   ...
};

if not dynamically allocate it and transfer ownership:

class max_likelihood {  
public: 
   std::unique_ptr<MatrixXd> dat;
   max_likelihood(std::unique_ptr<MatrixXd> dat_in) : dat( std::move(dat_in) ) {}
   ...
};

Usually having reference in a class is not a good idea, first of all you need to be careful for not getting dangling reference, second - you will have complications if you decide to allow your object to be copied and/or assigned.

Slava
  • 43,454
  • 1
  • 47
  • 90
  • reading a bit about the problem I think this is a very good solution. If I were to have more arguments in addition to dat, would the syntax for that be like that of inheritance, i.e. separated by commas? – Hirek Nov 05 '18 at 16:44
  • This answer is pretty silly, as the exact same thing can be accomplished without using move semantics and instead storing a reference to a MatrixXd& as a member (and avoid the copy just the same, and no issues with dangling references if using RAII correctly for the MatrixXd object.) The real reason to use Eigen::Ref is to allow your code to take general Eigen types as inputs (see Eigen doc for details.) – ldog Feb 16 '20 at 07:55
1

The member variable dat is a const reference that needs to be initialized.

max_likelihood(const Ref<const MatrixXd>& argdat):dat(argdat){}

You may want to use a non const ref instead:

class max_likelihood {
public:
Ref<const MatrixXd> dat;
max_likelihood(const Ref<const MatrixXd>& dat):dat(argdat){}

At least you get a local ref.

Matthieu Brucher
  • 21,634
  • 7
  • 38
  • 62
  • 2
    This solution is way too dangerous and I do not think OP understand all implications. – Slava Nov 05 '18 at 15:58
  • 1
    Removed the const Ref&, I agree that it is not useful, will be slower and may crash. – Matthieu Brucher Nov 05 '18 at 16:01
  • @Slava very likely yes, So I was just about to write an example but thought my q is sufficiently trivial that it can be solved on the spot. I have tried to pre-declare dat as either a MatrixXd in my header (resulting in a copy) or as a reference. Is that what you meant and what this solution does? Or the comment is right. :-) – Hirek Nov 05 '18 at 16:01
  • 2
    @Hirek getting const reference and keeping it is error prone solution - for example you can easily pass temporary and get dangling reference. In general - having reference (const or not) in a class is not a good idea. – Slava Nov 05 '18 at 16:05
  • @Slava ok so you are actually saying that it is better in this case to pass by value, i.e. hand the physical data over to the class (and then pass around by reference internally I suppose) just in terms of style? – Hirek Nov 05 '18 at 16:06
  • It depends on what you want to do. Slava's solution moves the data around. If you just need to reference data that is available and stored someplace else, then you should do what I used. – Matthieu Brucher Nov 05 '18 at 16:08
  • @MatthieuBrucher I do not think OP needs reference itslef quote "I get functioning code but end up creating a copy of dat, which I would like to avoid." – Slava Nov 05 '18 at 16:10
  • Doesn't mean that the moved matrix is not used later in the process. – Matthieu Brucher Nov 05 '18 at 16:11
  • @MatthieuBrucher yes, I wish to pass by reference to avoid having to copy relatively large data sets, the reference itself directly is not used. I just need to access the data (by memory location) and the data do not change. – Hirek Nov 05 '18 at 16:12
  • @MatthieuBrucher hmm, so I take some of its columns, copy those into new objects etc. but they will not change themselves – Hirek Nov 05 '18 at 16:13
  • I would then use Ref, yes, like what I did, and then I would use views ont he Eigen matrices to do my computations. – Matthieu Brucher Nov 05 '18 at 16:14
0

You can use the initializer list:

struct max_likelihood { 
    MatrixXd& dat
    max_likelihood(MatrixXd& dat_in) : dat(dat_in) {}
};
463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
0

You can set and access a reference like this:

class max_likelihood {
public:
   max_likelihood( const MatrixXd& input_dat): dat(input_dat) { }
   const MatrixXd& dat;
};

But you cannot change the reference, i.e. re-assign it to another object to reference.

If you need this functionality, then you have to change the member variable to be a pointer, then you can easily change the pointer. And if you don't want the users of your class having to use a pointer, you could add a method that returns a reference.

If you implement the pointer solution, keep in mind that the original object has to persist as long as anypody tries to access it using you max_likelihood class. Maybe you should use a std::shared_ptr<> to prevent memory leaks.

Rene
  • 2,466
  • 1
  • 12
  • 18