views:

76

answers:

3

I'm an intermittent programmer and seem to have forgotten a lot of basics recently.

I've created a class SimPars to hold several two-dimensional arrays; the one shown below is demPMFs. I'm going to pass a pointer to an instance of SimPars to other classes, and I want these classes to be able to read the arrays using SimPars accessor functions. Speed and memory are important.

I know life is often simpler with vectors, but in this case, I'd really like to stick to arrays.

How do I write the accessor functions for the arrays? If I'm interested in the nth array index, how would I access it using the returned pointer? (Should I write a separate accessor function for a particular index of the array?) What's below is certainly wrong.

// SimPars.h
#ifndef SIMPARS_H
#define SIMPARS_H
#include "Parameters.h" // includes array size information

class SimPars {
 public:
  SimPars( void );
  ~SimPars( void );

  const double [][ INIT_NUM_AGE_CATS ] get_demPMFs() const;

 private:
   double demPMFs[ NUM_SOCIODEM_FILES ][ INIT_NUM_AGE_CATS ];

};
#endif


// SimPars.cpp
SimPars::SimPars() {
 demPMFs[ NUM_SOCIODEM_FILES ][ INIT_NUM_AGE_CATS ];
 // ...code snipped--demPMFs gets initialized...
}

//...destructor snipped
const double [][ INIT_NUM_AGE_CATS ] SimPars::get_demPMFs( void ) const {
  return demPMFs; 
}

I would greatly appreciate some kind of explanation with proposed solutions.

+1  A: 
const double (* get_demPMFs() const)[INIT_NUM_AGE_CATS];

Or, use typedef (but that doesn't seems cleaner...).

class SimPars {
    typedef const double (*ConstDemPMFType)[INIT_NUM_AGE_CATS];

    double demPMFs[NUM_SOCIODEM_FILES][INIT_NUM_AGE_CATS];
public:
    ConstDemPMFType get_demPMFs() const;
};

Note that you can't return an array (g++ refuses the compile). But an array of array can be decayed to a pointer to array, so the latter is returned.

KennyTM
`(* get_demPMFs() const)` -> ah, that's where the parenthesis and the const must go, I was fighting the C declarator syntax for 5 minutes and gave up, retreating to good-old typedef :)
FredOverflow
@Fred this is where `identity` excels. `identity<const double[INIT_NUM_AGE_CATS]>::type *get_demPMFs() const;`
Johannes Schaub - litb
+2  A: 

Basically, you have three options: return the entire array by reference, return the first row by pointer, or return the entire array by pointer. Here is the implementation:

typedef double array_row[INIT_NUM_AGE_CATS];

typedef array_row array_t[NUM_SOCIODEM_FILES];

array_t demPMFs;

const array_t& return_array_by_reference() const
{
    return demPMFs;
}

const array_row* return_first_row_by_pointer() const
{
    return demPMFs;
}

const array_t* return_array_by_pointer() const
{
    return &demPMFs;
}

And here are the use cases:

SimPars foo;

double a = foo.return_array_by_reference()[0][0];
double b = foo.return_first_row_by_pointer()[0][0];
double c = (*foo.return_array_by_pointer())[0][0];

How would I return just the nth row of the array?

Again, you have three choices:

const array_row& return_nth_row_by_reference(size_t row) const
{
    return demPMFs[row];
}

const double* return_first_element_of_nth_row_by_pointer(size_t row) const
{
    return demPMFs[row];
}

const array_row* return_nth_row_by_pointer(size_t row) const
{
    return demPMFs + row;
}
FredOverflow
@Fred: Thank you. How would I return just the nth row of the array?
Sarah
@Sarah: I updated my post. In both cases, I would prefer the first solution, returning the complete thing that you're interested in by reference.
FredOverflow
A: 

Logically speaking there is this question with a data member. Should users be allowed to modify it or not. If you want to give another class full access to the member, you don't necessarily need getter/setter, especially if you are the only user. You can just make the member public.

If your class would be better off controlling how users access the member, then you could use a getter only to enforce read only access. The simplest way to do this if you don't want to get all confused about the 2-dimensional arrays is to just have an inline function fetching the element for the user class:

const double& getElem( int x, int y ) const { return demPMF[x][y] }

It makes sense to do bounds checking here, but considering that you insist on using arrays, and if your profiler proves that you can't afford it, this function would just allow access to your array.

If you want further elaboration, post a comment...

ufotds
How is passing the entire array out by const reference any less safe?
FredOverflow
O, it is definitely not less safe, but it is more confusing, at least for me this is much simpler. I'm still trying to work out the syntax of yours and Kenny's answers.
ufotds