What Is the Safe Way to Fill Multidimensional Array Using Std::Fill

What is the safe way to fill multidimensional array using std::fill?

The simple way to initialize to 0 the array is in the definition:

char flags[26][80] = {};

If you want to use std::fill, or you want to reset the array, I find this a little better:

char flags[26][80];
std::fill( &flags[0][0], &flags[0][0] + sizeof(flags) /* / sizeof(flags[0][0]) */, 0 );

The fill expressed in terms of the array size will allow you to change the dimensions and keep the fill untouched. The sizeof(flags[0][0]) is 1 in your case (sizeof(char)==1), but you might want to leave it there in case you want to change the type at any point.

In this particular case (array of flags --integral type) I could even consider using memset even if it is the least safe alternative (this will break if the array type is changed to a non-pod type):

memset( &flags[0][0], 0, sizeof(flags) );

Note that in all three cases, the array sizes are typed only once, and the compiler deduces the rest. That is a little safer as it leaves less room for programmer errors (change the size in one place, forget it in the others).

EDIT: You have updated the code, and as it is it won't compile as the array is private and you are trying to initialize it externally. Depending on whether your class is actually an aggregate (and want to keep it as such) or whether you want to add a constructor to the class you can use different approaches.

const std::size_t rows = 26;
const std::size_t cols = 80;
struct Aggregate {
char array[rows][cols];
};
class Constructor {
public:
Constructor() {
std::fill( &array[0][0], &array[rows][0], 0 ); // [1]
// memset( array, 0, sizeof(array) );
}
private:
char array[rows][cols];
};
int main() {
Aggregate a = {};
Constructor b;
}

Even if the array is meant to be public, using a constructor might be a better approach as it will guarantee that the array is properly initialized in all instances of the class, while the external initialization depends on user code not forgetting to set the initial values.

[1] As @Oli Charlesworth mentioned in a comment, using constants is a different solution to the problem of having to state (and keep in synch) the sizes in more than one place. I have used that approach here with a yet different combination: a pointer to the first byte outside of the bidimensional array can be obtained by requesting the address of the first column one row beyond the bidimensional array. I have used this approach just to show that it can be done, but it is not any better than others like &array[0][0]+(rows*cols)

what's the most efficient way to fill 2d std::array and std::vector?

As referenced from here using std::fill on a 2D int vector, Nested loop may be the best option to fill them faster
(Based on comment by @juanchopanza )

vector<vector<int> > a(3,vector<int>(3));

for (int i = 0 ; i < 3; i++)
fill(a[i].begin(),a[i].end(),falseValues);

For c++14 and above you can also use

for_each(a.begin(),a.end(),[](vector<int>& aa)
{fill(aa.begin(),aa.end(),falseValues);});

How to fill a part of a multidimensional array in C++?

You can't initialize a multidimensional array like that. If you want to do so do it like this:

#include<iostream>
using namespace std;

int main()
{

int m[4][4][3][3] = {1,0,1, //1
1,1,1,
1,0,1,

1,1,1, //2
0,1,0,
1,1,1,

1,0,1, //3
1,1,1,
1,0,1,

// ...
// ...

1,0,1, //16
1,1,1,
1,0,1};

for(int i=0;i<4;++i)
for(int j=0;j<4;++j) {
for(int p=0;p<3;++p) {
for(int q=0;q<3;++q)
std::cout<<m[i][j][p][q];
std::cout<<std::endl;
}
std::cout<<std::endl;
}
}

Or else use 4 for loops to assign your array. You must always remember that a multidimensional array is nothing but a single dimensional array in memory, so initialize it like a single dimensional only.

c++11 using std::fill to fill a 2D dynamically allocated array

Unlike a stack allocated 2D array, a dynamic 2D array is not guaranteed to be a contiguous range. It is however a contiguous range of pointers, but each pointer in the array may point to non-contiguous memory areas. In other words, the first element of data + i + 1 may not necessarily follow the last element of the array pointed by data + i. If you wonder why a stack-allocated 2D array is contiguous, it is because when you declare something like

double data[10][20];

then the compiler understands it as array of 10 (contiguous) elements, each element of type double[20]. The latter type is also an array, which guarantees contiguous elements, so the double[20] elements (i.e. 20 double one after the other) are stacked one after the other in the memory. double[10][20] is is strikingly different from double**.

That's why std::fill or std::memset gives you headaches, as they both assume a contiguous range. Therefore in your case a nested loop seems to be the simplest way of filling the array.

In general, it is much better to use a 1D array in which you "mimic" the 2D access, exactly for the reasons mentioned above: data locality. Data locality implies fewer cache missed and better overall performance.



Related Topics



Leave a reply



Submit