0

I would like to make an array like this:

double array[variable][constant];

Only the first dimension is variable. Declaring this with a variable as the first dimension gives initialization errors. Is there a simple way to do this with pointers or other basic types?

juanchopanza
  • 223,364
  • 34
  • 402
  • 480
Machinus
  • 109
  • 10
  • You probably want `std::vector>(variable)`. – Mankarse Aug 03 '14 at 20:15
  • 1
    I would write a class to wrap a single `std::vector`. – juanchopanza Aug 03 '14 at 20:22
  • @juanchopanza why? For speed reasons? – vsoftco Aug 03 '14 at 20:36
  • 1
    @vsoftco Yes, the single vector to ensure the data are all contiguous, and the wrapper to make sure the invariants can be maintained. – juanchopanza Aug 03 '14 at 20:38
  • @juanchopanza Note the vector contains array, so data is contiguous. Could you explain what "invariants can be maintained" means, please? – Neil Kirk Aug 03 '14 at 21:11
  • @NeilKirk The data in a vector of `std::array` would be in the same data block, but all the elements need not be contiguous. The standard allows for this, unfortunately. For invariants, I mean the case where `variable` and/or `constant` may be fixed, set at runtime, but at construction. – juanchopanza Aug 03 '14 at 21:14
  • @juanchopanza I still don't understand. Both vector and array have contiguous elements. It's in the standard. – Neil Kirk Aug 03 '14 at 21:17
  • @NeilKirk Imagine if an array had a tiny little something after its data elements. Well, the standard does not rule that out, which means that in a vector or array of arrays, the elements themselves are not guaranteed to be contiguous, even if they are all in the same block. It is a pity, because it is even hard to imagine an implementation that would do that. – juanchopanza Aug 03 '14 at 21:19

2 Answers2

1

Variable length arrays didn't make it in the latest C++ standard. You can use std::vector instead

std::vector<std::vector<double> > arr;

Or, to fix for example the second dimension (to 10 in this example), you can do

std::vector<std::array<double, 10> > arr1; // to declare a fixed second dimension

Otherwise you need to use old pointers,

double (*arr)[10]; // pointer to array-of-10-doubles

In light of @Chiel's comment, to increase performance you can do

typedef double (POD_arr)[10];
std::vector<POD_arr> arr;

In this way, you have all data stored contiguously in the memory, so access should be as fast as using a plain old C array.

PS: it seems that the last declaration is against the standard, since as @juanchopanza mentioned, POD arrays do not satisfy the requirements for data to be stored in an STL array (they are not assignable). However, g++ compiles the above 2 declarations without any problems, and can use them in the program. But clang++ fails though.

vsoftco
  • 55,410
  • 12
  • 139
  • 252
  • I would strongly advise against the nested types in performance critical cases, since the total array won't be contiguous in memory – Chiel Aug 03 '14 at 20:25
  • @Chiel, both `std::vector` and `std::array` are contiguous, but yes, the total object may not have the data contiguous because a `std::array` occupies more than the wrapped array inside. Then I guess one can define a `std::vector`, where `POD_arr` is just a `typedef double (POD_arr)[10]`. This should make everything contiguous, if I'm not wrong somehow. – vsoftco Aug 03 '14 at 20:31
  • You can't store plain arrays in a standard library container. The vector of arrays is quite a good solution. The data are in a single block. There *may* be padding between the arrays, but the effect of that would be minimal. The only issue is if there is a requirement for all the elements to be contiguous. – juanchopanza Aug 03 '14 at 20:36
  • @juanchopanza, are you sure about not being able to store POD arrays? I just test it and it seems to work, initialized fine, write/read OK, no segfauls. – vsoftco Aug 03 '14 at 20:40
  • @vsoftco Pretty sure, plain arrays are not assignable or copyable. – juanchopanza Aug 03 '14 at 20:41
  • @vsoftco I meant indeed the total object, which is quite often essential for high performance with multi-dimensional objects. – Chiel Aug 03 '14 at 20:43
  • @juanchopanza Another `g++` bug, I keep finding them every day :) So the code compiles with `g++`, can assign elements to the `vector`, can the display them etc. However, as you mentioned, cannot copy/move/assign it. However, `clang++` does NOT compile it. – vsoftco Aug 03 '14 at 20:43
  • `std::array` is a template - I don't think it should need any data beyond a `T[N]`, so that `std::vector >` ought to store all of the data in a contiguous 80 byte block. – sfjac Aug 03 '14 at 20:58
  • @sfjac doesn't it have to store some pointers to member functions? – vsoftco Aug 03 '14 at 21:00
  • If you mean a vtable pointer, `std::array` is unlikely to have any virtual functions. (Whether this is a language requirement I don't know but as a user of this sort of template array class I would definitely be disappointed if it did.) – sfjac Aug 03 '14 at 21:07
  • @sfjac, no, of course, STL containers don't have virtual members, as far as I know. I meant member functions, but now I found out that they are not actually stored in the instantiation. So you are right, the only issue may be padding, as juanchopanza mentioned, however it shouldn't make a big difference. Although it seems there is no padding according to `sizeof`, however it is not guaranteed. – vsoftco Aug 03 '14 at 21:12
  • Because of its template nature, you can static_assert on the size - I think this should suffice to check at compile time whether you will have problems; e.g. `static_assert(6*sizeof(int) == sizeof(std::array), "sizeof array inconsistency");` – sfjac Aug 03 '14 at 22:51
0

You could do something like that, but it is not a true 2D array. It is based on the general idea that internally a multiple dimension array is necessarily linear with the rule that for an array of dimensions (n, m) you have : array2d[i, j] = array1d[j + i*m]

#include "iostream"

using namespace std;

class dynArray {
private:
    double *array;
    int dim2;
public:
    dynArray(int variable, int constant) {
        array = new double[variable * constant];
    dim2 = constant;
    }
    ~dynArray() {
        delete array;
    }

    double value(int i, int j) {
        return array[j + i * dim2];
    }

    double *pt(int i, int j) {
        return array + j + i * dim2;
    }
};

int main(int argc, char*argv[]) {
    dynArray d(3,4);
    *d.pt(2,3) = 6.;
    cout << "Result : " << d.value(2,3) << endl;
    return 0;
}
Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252