Make initialization variables accessible to several attributes initialization methods

Viewed 59

I write a class using sparse matrices. It happens that for both of them, their non-zeros are on the same (i,j)s. As I have to compute these (i,j)s, I'd prefer to have to do it only once.

Currently, I do it separately and my constructor looks like this:

class C
{
    private:
        matrix matA;
        matrix matA;
        holder ijs;

    private:
        matrix initMatA();
        matrix initMatA();
        holder init_ijs(int, int);

    public:
        C(int, int);
};

C::C(int foo, int bar) : init_ijs(foo, bar), matA(initMatA()), matB(initMatB())
{
}

as I've read that it is best practice to use initialization list (and actually, when I first wrote it, if I remember correctly it was impossible to instantiate my matrices otherwise (EDIT: a default constructor seems to fix it?)). If it was Python, I could write something like

def initMats(foo, bar):
    ...
    return matA, matB

If think the C++ way would be something like

void initMats(int foo, int bar, matrix &matA, matrix &matB)
{
    ...
}

but I guess I cannot pass reference to objects that have not yet been constructed. Any clue on a way to solve this? My idea was to first create the (i,j)s list as an attribute to my class so I can later use it in my initA and initB methods, but I will not be needing it afterward I don't think it's the best way to do.

2 Answers

If I understand the question correctly, you wish to:

  • take two sparse matricies (or similar) as inputs
  • compute IJ for the two matricies
  • apply IJ to them both before continuing
  • construct the Class with the modified matricies.

The constraint is that the matricies are not default-constructible.

I think I would do it something like this:

// A class to hold the result of computing ij
struct ij_holder
{
    // whatever goes here
};

// a sparse matrix class
struct sparse_matrix
{
    // let's say it's not default-constructible
    sparse_matrix(int, int , int , int);
};

// apply ij to sparse matrix m, returning the modified matrix
sparse_matrix apply(ij_holder const& ij, sparse_matrix m)
{
    // whatever goes here to modify m

    return m;
}

// compute ij from two matricies
ij_holder compute_ij(sparse_matrix const& a, sparse_matrix const& b);


struct Class
{
    // public constructor written in terms of private constructor
    Class(sparse_matrix const& foo, sparse_matrix const& bar)
    : Class (compute_ij(foo, bar), foo, bar)
    {}

private:
    // private constructor
    Class(ij_holder ij, sparse_matrix const& foo, sparse_matrix const& bar)
    : foo_(apply(ij, foo))
    , bar_(apply(ij, bar))
    {}


sparse_matrix foo_;
sparse_matrix bar_;

};

Init methods are not idiomatic in C++. Use constructors.

You can achieve what you want with a delegating constructor (C++11 and newer). First, you need a constructor for the matrix class that accepts an (i,j)-list.

  using ijlist = ...; //probably some kind of an array
  class matrix {
      ...
      matrix(const ijlist& ijs) { ... }
      ...
  };

Then you write a constructor for C that accepts an ijlist and passes it to the two matrix data members:

  class C {
      ...
      matrix matA, matB;
      ...
      C(const ijlist& ijs) : matA(ijs), matB(ijs) { ... }

Now you can compute your (i,j)-list in an auxiliary function and pass it to this constructor from any other constructor:

  C() : C(compute_ijs()) { ... }
Related