8

I'm familiar with C++ constructors & initializers:

class Foo {
   int x;
public:
   Foo(int _x) : x(_x) {}
};

Foo foo1(37);
Foo foo2(104);

My question is that I have to implement a class that has a member which is a 3x6 array. How would I do something similar to the above?

class Bar {
   int coeff[3][6];
public:
   // what do I do for a constructor????
};

edit: for a plain array, I would do the following, I just don't know how to do it for a class:

 static int myCoeffs[3][6] = 
 {{  1,  2,  3,  4,  5,  6}, 
  {  7,  8,  9, 10, 11, 12},
  { 13, 14, 15, 16, 17, 18}};

edit 2: For various reasons (e.g. this is an embedded system w/ limitations) I need to not use Boost, so if it offers a solution I can't use it.


UPDATE: I'm not tied to an initializer. It's OK to do it in the constructor body, and it doesn't have to be inline, either. I'm just looking for a correct way to construct an instance of a class which needs an array of coefficients, without messing up pointer assignment or something.

3
  • Which version of C++? If you are using the current (C++03) version of the standard there's no way to mimic an initializer. Commented Mar 7, 2011 at 16:12
  • "old-school" C++ -- this is for an embedded system, I have no idea which version of the standard, and even 2003 might be too recent. Commented Mar 7, 2011 at 16:14
  • 2003 is the first standardized version. Commented Mar 7, 2011 at 16:14

6 Answers 6

6

You can't. In C++03 you can't initialize an array in a ctor-initalization list. However you can do it in the constructor body (technically it isn't an initialization any more).

That is

struct x
{
    int a[4];
    x():a({1,2,3,4}) //illegal
    {
        a[0] = 1;
        etc. 
    }
};

Edit: after question edit here's a way to do it

#include <algorithm>
struct x
{
   int arr[3][4];
   x(int (&arg)[3][4])
   {
      std::copy(&arg[0][0], &arg[0][0]+3*4, &arr[0][0]);
   }

};
Sign up to request clarification or add additional context in comments.

12 Comments

Well, that's OK, I just need some "nice" way to do it.
@Jason: The only "nice" way I can think of is to initialize them memberwise in the ctor, like a[0] = 1; a[1] = 23; etc..
yuck. argh, I guess I'll just pass in an array, and use a pair of for loops to copy the elements.
@Billy: Not in C++03. Not sure about C++0x
@Armen Some hair in your code: temp should be static and const; the arguments to std::copy should be pointers to int, e.g. &temp[0][0], &temp[0][0] + 3 * 4 - so no +1 yet
|
2

I don't know if it sounds too obvious but, why don't just copy the values?

class Foo {
    static const int X = 3;
    static const int Y = 6;

    int mCoeff[X][Y];

    void setCoeff(int coeff[X][Y]) {
        for (int i = 0; i < X; i++) {
            for (int j = 0; j < Y; j++) {
                mCoeff[i][j] = coeff[i][j];
            }
        }
    }
public:
    Foo(int coeff[X][Y]) {
        setCoeff(coeff);
    }

};

Hope it helps. Regards.

10 Comments

This is wrong for the same reason my answer was initially wrong.
It may not be clever or the most efficient way to do it, but it works with my compiler.
OK, so I had to change int coeff[X][Y] to int **pcoeff.
@Jason: That's completely wrong. @redent84's code works but I can't seem to figure out why (because it's seems to be exactly the same as what I posted below but mine didn't compile..). int [x][y] is not an array of pointers to arrays. It is a single memory block. int ** is a completely different type.
As Jason suggested, I changed method signature so it can take dynamically allocated array of integers. This way array boundaries are not checked and you could get segmentation violation faults.
|
1

In C++03, since you cannot initialize an array in the initialization-list, you can write a generic function template to fill an array with a given array, as demonstrated in the following example,

template<typename T, size_t N>
void array_fill(T (&dest)[N], T (&src)[N])
{
   for ( size_t i = 0 ; i < N ; i++ )
       dest[i] = src[i];
}
struct A
{
   int a[5];
   A(int (&i)[5]) { array_fill(a, i); }
   void print() 
   {
      for ( int i = 0 ; i < 5 ; i++ ) cout << a[i] << " ";
   }
};
int main() {
        int a[5] = {1,2,3,4,5};
        A obj(a);
        obj.print();
        return 0;
}

Output:

1 2 3 4 5

Run at ideone: http://ideone.com/pFcrv

Well, there is already std::copy which can be used as well.

2 Comments

1. I would implement array_fill in terms of std::copy because in many STLs that'll decompose to a call to memcpy which may be faster on the target hardware. 2. This doesn't work for the OP's use case because he's dealing with multidimensional arrays.
@Billy: I was thinking the same. I'm too lazy to implement it myself, as I'm watching TV :D. And that is why I mentioned std::copy in the last line. array_fill can be written elegantly to handle multi-dimensional array, there std::copy might help a lot!
1

You can't (in general) pass the arbitrary multidimensional array to a function in C or C++ as one would in Java (I mention Java because that's where your question history suggests your experience lies).

There's really no way to support anything like array initializers for your class in the current standard, though there are some plans to change this in the next version, C++0x.

If you want this to have the flexibility of, say, Java's arrays (where clients can change the size of the pointed to array, you have a few options. The first and best would to be to use std::vector<>, which implements a dynamic array for you, but you might be restricted on that by your embedded platform. You can also implement things yourself as a single dimensional array, and accept a dynamic memory block. Example:

class Foo
{
    int *theArray_;
    unsigned int rows_;
    unsigned int cols_;
public:
    Foo(int *theArray, int rows, int cols)
        : theArray_(theArray)
        , rows_(rows)
        , cols_(cols)
    { }
    void UseTheArray()
    {
        //Access array[5][6]
        theArray[5*cols+6];
    }
};

Note that in this case the callee is responsible for handing the memory. Also consider using a std::auto_ptr above instead of the raw pointer to make it clear who's responsible for nuking the memory block when the object is destroyed.

Also note that you shouldn't use the name _x - names beginning with an underscore have a whole bunch of rules attached to them about which you probably want to avoid thinking.

EDIT: This is a segment of my original answer; it is wrong:

A multidimensional array in C++ is just a single memory block. It's possible to accept a multidimensional array like this only in one case -- where you know the exact dimensions of the array beforehand in the class. Then you could write something like:

class Foo {
   int coeff[3][6];
public:
   Foo(int _x[3][6]) : coeff(_x) {}
};

Note however that the size of the array is fixed and cannot be changed by clients of your class.

9 Comments

"should" -> "shouldn't"? (also what's the issue with underscore? is it because of C++ name-mangling producing automated functions that assume use of the identifier namespace with a leading underscore?)
The initializer you mention: does that automatically copy the memory, or does it use the memory block you pass in?
@Billy: This is ABSOLUTELY illegal! I assure you!. The argument you pass is actually a pointer to an array, not a two-dimensional array!
@Armen: Hmm.... I don't see why it doesn't work. But apparently it doesn't. Gah! (Sometimes I wonder why multidimensional arrays are even in the language!)
Argh. I tried the above Foo example you gave verbatim, and I got the error: error #776: only "()" is allowed as initializer for array member "Foo::coeff"
|
-1

If you have to go that way, I would just go for a for loop iterating the elements of the bi-dimensional array and initializing them. Or if if you're going for speed, something like a memset would do the trick.

memset(&coeff,0,3*6*sizeof(int)) 

2 Comments

Hi Billy, sorry but what does OP's mean?
Original Post / Original Poster
-1

You can do it this way:

#include <algorithm>
class Bar 
{    
    int coeff[3][6]; 
public:    // what do I do for a constructor???? 
    Bar()
    {
        int myCoeffs[3][6] = 
        {
            {  1,  2,  3,  4,  5,  6},    
            {  7,  8,  9, 10, 11, 12},   
            { 13, 14, 15, 16, 17, 18}
        }; 
        std::swap(coeff, myCoeffs);
    }
};

3 Comments

Why swap? What's wrong with coeff = myCoeffs? But this doesn't solve the OP's problem anyway because you're not passing the parameters into the constructor.
...but I need to pass in coefficients to the constructor. Otherwise, each instance of the object will get the same coefficients.
@Billy I have (maybe too early) totally assimilated move semantics :)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.