C++ creating a 2D array using the size of a given vector, in a memory-safe manner [duplicate] - c++

This question already has answers here:
How to create a two dimensional array of given size in C++
(3 answers)
Closed 7 years ago.
How do I achieve the following:
std::vector<int> vec = { 1, 2, 3 };
const int N = vec.size();
// Now create NxN 2D array.
First, I know I could do it with new but I'd have to remember to delete it later, and I'd rather not have to handle deallocation of memory if possible.
Second, I can't declare the 2D array on the stack because N is not (and can't be in this case) a constant expression. (In any case I'm using VS2013 and it doesn't support constexpr.)
Third, I can't (or maybe don't know how to) use std::array because apparently "a local variable cannot be used as a non-type argument". (I copy-pasted this from the VS2013 compile dialogue and have little understanding regarding this point).
Fourth, I'm thinking of using unique_ptr. The problem is, I know how to use unique_ptr for a 1D array, like std::unique_ptr<int> arr{ new int[N] }, but can't figure out how to do it for a 2D array.
Lastly, I know I can always write my own thin wrapper around a C-style array that's always created on the heap, or write my own 2D array class. But is there a native or standard library way of doing this in C++ (C++11)?

std::experimental::array_view is a view to an n-dimensional array with dynamic size bounds on a packed buffer.
So one approach is to create a contiguous buffer (say, a std::vector<T>, or a std::unique_ptr<T[]>, and then wrap an array_view<T,2> around it.
Access through the view object, and it will have the operations you should expect from an array. The storage is managed separately from the way of looking at the storage.
Writing a simplified version of this array_view for the 1 and 2 dimensional case isn't tricky. But the result is your code is high performance, and very clear at point of use. The glue code (for array_view) can be a bit tricky, but once tested it should be solid: and the likelihood that a similar construct will be added to std shortly means it won't remain obscure for long.
In my experience, once I have a solid array_view type, I use it as a drop-in replacement for where I was (inefficiently) using std::vector to pass bundles of data around in the past.
If you want to write your own, I'd skip the bits about bounds and indexes, and just implement slicing -- [] on a 2nd dimension array_view returns a 1st dimension array_view, and [] on a 1st dimension array_view returns a T&.

I suggest you write a class for it.
Example below: set() resizes it before setting values. The operator [] returns the column vector for that row, so when you apply the operator [] it returns the desired value. Let me know if you find any issue ;).
class 2DVector {
std::vector<std::vector<int>> m_items;
void set(int value, size_t row, size_t column) {
for (int i=m_items.size(); i<=row; i++) {
m_items.push_back(std::vector<int>());
}
for (int i=0; i<m_items.size(); i++) {
for (int j=m_items[i].size(); j<=column; j++) {
m_items[i].push_back(0);
}
m_items[row][column] = value;
}
std::vector<int> &operator [](size_t index) {
return m_items[index];
}
}
Usage:
2DVector v;
v.set(200, 0, 0);
v.set(201, 1, 0);
std::cout << v[0][0]; //prints 200
std::cout << v[1][0]; //prints 201

The standard library way of doing this is:
std::vector< std::vector<int> > vec2d (vec.size(), vec);
which will initialize each row with the values from vec. If you don't want to do this then leave off the final argument.

What about mimic a 2D array by 1D array?Like the way done by openCV2
pseudo codes
class 2DVector {
void set(int value, size_t row, size_t column) {
m_items[row * column_size + column];
}
int &operator [](size_t row, size_t column) {
return m_items[row * column_size + column];
}
private:
std::vector<int> m_items;
}
Or just use the boost::multi_array(Not sure about the performance is good enough for your case).

Related

Sorting a C 2D array via std::sort

I have a 2D array a[][40]. I'm trying to sort it by calling std::sort, and I have written the Compare function. However, C++ wants me to have a std::vector to be sorted, not a simple array and I want the sorted array to be a itself, I don't want to create another array and save the sorting result there. It seems there are a lot of ways to achieve that. I could think of five ways, but none of them seems to be efficient and working.
1)
Directly use std::sort(std::begin(a), std::begin(a) + something, cmp);
It doesn't work, because std::begin doesn't know how to point to the beginning of a 2D array. Furthermore, it'd sort incorrectly even if it compiled, since a 2D array is not an array of references to arrays, but consecutive arrays (unlike Java)
Playground: https://godbolt.org/g/1tu3TF
2)
std::vector<unsigned char[40]> k(a, a + x);
std::sort(k.begin(), k.end(), cmp);
Then copy everything back to a
It doesn't work, because it's a 2D array, and it can't be sorted this way, using std::sort. In contrast to the first trial, this one uses twice as much as memory, and copies everything twice (if it worked)!
Playground: https://godbolt.org/g/TgCT6Z
3)
std::vector<int> k(x);
for (int i = 0; i < x; k[i] = i, i++);
std::sort(k.begin(), k.end(), cmp2);
Then change the order of a to be the same of k;
The idea is simple, create a vector of representative "pointers", sort them (as the cmp2 function secretly accesses a and compares the values), then make a have the same order with k.
In the end, the re-ordering loop will be very complex, will require a large, temporary variable. Besides, for cmp2 to access the values of a, a global variable-pointer that points to a must be created, which is "bad" code.
Playground: https://godbolt.org/g/EjdMo7
4)
For all unsigned char[40], a struct can be created and their values can be copied to structs. Comparison and = operators will need to be declared. After sorted, they can be copied back to a.
It'd be a great solution if the arrays didn't have to be copied to structs to use struct's operators, but they need to be copied, so all values will be copied twice, and twice-as-needed memory will be used.
5)
For all unsigned char[40], a struct that has a pointer to them can be created. They can be sorted by the pointed values, and the result can be saved to a pointer array.
It's probably the best option, although the result is a pointer array instead a. Another reason on why it's good is it doesn't move the arrays, but the pointers.
To sum up, I need to sort the 2D array a[][40] via std::sort, but I haven't decided on the best way. It seems there's a "best way to do that" which I can't think of. Could you please help me?
EDIT: To clarify, I want {{3,2}{1,4}} to become {{1,4}{3,2}}
The problem is not in iterating a 2D array. Provided the columns size is a constexpr value, pointers to arrays are nice iterators.
But all C++ sort (or mutating) algorithms require the underlying type to be move constructible and move assignable and an array is not assignable. But wrapping the underlying arrays can be enough:
template <class T, int sz>
class wrapper {
T* base;
bool own; // a trick to allow temporaries: only them have own == true
public:
// constructor using a existing array
wrapper(T* arr): base(arr), own(false) {}
~wrapper() { // destructor
if (own) {
delete[] base; // destruct array for a temporary wrapper
}
}
// move constructor - in fact copy to a temporary array
wrapper(wrapper<T, sz>&& src): base(new T[sz]), own(true) {
for(int i=0; i<sz; i++) {
base[i] = src.base[i];
}
}
// move assignment operator - in fact also copy
wrapper<T, sz>& operator = (wrapper<T, sz>&& src) {
for(int i=0; i<sz; i++) {
base[i] = src.base[i];
}
return *this;
}
// native ordering based on lexicographic string order
bool operator < (const wrapper<T, sz>& other) const {
return std::char_traits<char>::compare(base, other.base, sz) < 0;
}
const T* value() const { // access to the underlying string for tests
return base;
}
};
Then, you can sort a C compatible 2D array with any C++ sort algo:
std::vector<wrapper<char, 40> > v { &arr[0], &arr[sz] }; // pointer are iterators...
std::sort(v.begin(), v.end()); // and that's all!
for (int i=0; i<sz; i++) { // control
std::cout << arr[i] << std::endl;
}
The overhead is a vector of structures containing a pointer and a bool, but what is sorted is actually the original 2D array.
Of course, as the C library is accessible from C++, qsort would certainly be easier for sorting a C compatible 2D array. But this way allows the use of stable_sort or partial_sort if they are relevant.

C++ N nested vectors at runtime

In C++ (with or without boost), how can I create an N dimensional vectors where N is determined at runtime?
Something along the lines of:
PROCEDURE buildNVectors(int n)
std::vector < n dimensional std::vector > *structure = new std::vector< n dimensional std::vector >()
END
If passed 1, a vector would be allocated. If passed 2, a 2d nested matrix would be allocated. If passed 3, a 3d cube is allocated. etc.
Unfortunately you will not be able to do this. A std::vector is a template type and as such it's type must be known at compile time. Since it's type is used to determine what dimensions it has you can only set that at compile time.
The good news is you can make your own class that uses a single dimension vector as the data storage and then you can fake that it has extra dimensions using math. This does make it tricky to access the vector though. Since you will not know how many dimensions the vector has you need to have a way to index into the container with an arbitrary number of elements. What you could do is overload the function call operator operator with a std::intializer_list which would allow you to index into it with something like
my_fancy_dynamic_dimension_vector({x,y,z,a,b,c});
A real rough sketch of what you could have would be
class dynmic_vector
{
std::vector<int> data;
int multiply(std::initializer_list<int> dims)
{
int sum = 1;
for (auto e : dims)
sum *= e;
return sum;
}
public:
dynmic_vector(std::initializer_list<int> dims) : data(multiply(dims)) {}
int & operator()(std::initializer_list<int> indexs)
{
// code here to translate the values in indexes into a 1d position
}
};
Or better yet, just use a boost::multi_array

std::vector and contiguous memory of multidimensional arrays

I know that the standard does not force std::vector to allocate contiguous memory blocks, but all implementations obey this nevertheless.
Suppose I wish to create a vector of a multidimensional, static array. Consider 2 dimensions for simplicity, and a vector of length N. That is I wish to create a vector with N elements of, say, int[5].
Can I be certain that all N*5 integers are now contiguous in memory? So that I in principle could access all of the integers simply by knowing the address of the first element? Is this implementation dependent?
For reference the way I currently create a 2D array in a contiguous memory block is by first making a (dynamic) array of float* of length N, allocating all N*5 floats in one array and then copying the address of every 5th element into the first array of float*.
The standard does require the memory of an std::vector to be
contiguous. On the other hand, if you write something like:
std::vector<std::vector<double> > v;
the global memory (all of the v[i][j]) will not be contiguous. The
usual way of creating 2D arrays is to use a single
std::vector<double> v;
and calculate the indexes, exactly as you suggest doing with float.
(You can also create a second std::vector<float*> with the addresses
if you want. I've always just recalculated the indexes, however.)
Elements of a Vector are gauranteed to be contiguous as per C++ standard.
Quotes from the standard are as follows:
From n2798 (draft of C++0x):
23.2.6 Class template vector [vector]
1 A vector is a sequence container that supports random access iterators. In addition, it supports (amortized) constant time insert and erase operations at the end; insert and erase in the middle take linear time. Storage management is handled automatically, though hints can be given to improve efficiency. The elements of a vector are stored contiguously, meaning that if v is a vector where T is some type other than bool, then it obeys the identity &v[n] == &v[0] + n for all 0 <= n < v.size().
C++03 standard (23.2.4.1):
The elements of a vector are stored contiguously, meaning that if v is a vector where T is some type other than bool, then it obeys the identity &v[n] == &v[0] + n for all 0 <= n < v.size().
Also, see here what Herb Sutter's views on the same.
As #Als already pointed out, yes, std::vector (now) guarantees contiguous allocation. I would not, however, simulate a 2D matrix with an array of pointers. Instead, I'd recommend one of two approaches. The simpler by (by far) is to just use operator() for subscripting, and do a multiplication to convert the 2D input to a linear address in your vector:
template <class T>
class matrix2D {
std::vector<T> data;
int columns;
public:
T &operator()(int x, int y) {
return data[y * columns + x];
}
matrix2D(int x, int y) : data(x*y), columns(x) {}
};
If, for whatever reason, you want to use matrix[a][b] style addressing, you can use a proxy class to handle the conversion. Though it was for a 3D matrix instead of 2D, I posted a demonstration of this technique in previous answer.
For reference the way I currently create a 2D array in a contiguous memory block is by first making a (dynamic) array of float* of length N, allocating all N*5 floats in one array and then copying the address of every 5th element into the first array of float*.
That's not a 2D array, that's an array of pointers. If you want a real 2D array, this is how it's done:
float (*p)[5] = new float[N][5];
p [0] [0] = 42; // access first element
p[N-1][4] = 42; // access last element
delete[] p;
Note there is only a single allocation. May I suggest reading more about using arrays in C++?
Under the hood, a vector may look approximately like (p-code):
class vector<T> {
T *data;
size_t s;
};
Now if you make a vector<vector<T> >, there will be a layout like this
vector<vector<T>> --> data {
vector<T>,
vector<T>,
vector<T>
};
or in "inlined" form
vector<vector<T>> --> data {
{data0, s0},
{data1, s1},
{data2, s2}
};
Yes, the vector-vector therefore uses contiguous memory, but no, not as you'd like it. It most probably stores an array of pointers (and some other variables) to external places.
The standard only requires that the data of a vector is contiguous, but not the vector as a whole.
A simple class to create, as you call it, a 2D array, would be something like:
template <class T> 2DArray {
private:
T *m_data;
int m_stride;
public:
2DArray(int dimY, int dimX) : m_stride(dimX) : m_data(new[] T[dimX * dimY]) {}
~2DArray() { delete[] m_data; }
T* operator[](int row) { return m_data + m_stride * row; }
}
It's possible to use this like:
2DArray<int> myArray(30,20);
for (int i = 0; i < 30; i++)
for (int j = 0; j < 20; j++)
myArray[i][j] = i + j;
Or even pass &myArray[0][0] as address to low-level functions that take some sort of "flat buffers".
But as you see, it turns naive expectations around in that it's myarray[y][x].
Generically, if you interface with code that requires some sort of classical C-style flat array, then why not just use that ?
Edit: As said, the above is simple. No bounds check attempts whatsoever. Just like, "an array".

Passing array with unknown size to function

Let's say I have a function called MyFunction(int myArray[][]) that does some array manipulations.
If I write the parameter list like that, the compiler will complain that it needs to know the size of the array at compile time. Is there a way to rewrite the parameter list so that I can pass an array with any size to the function?
My array's size is defined by two static const ints in a class, but the compiler won't accept something like MyFunction(int myArray[Board::ROWS][Board::COLS]).
What if I could convert the array to a vector and then pass the vector to MyFunction? Is there a one-line conversion that I can use or do I have to do the conversion manually?
In C++ language, multidimensional array declarations must always include all sizes except possibly the first one. So, what you are trying to do is not possible. You cannot declare a parameter of built-in multidimensional array type without explicitly specifying the sizes.
If you need to pass a run-time sized multidimensional array to a function, you can forget about using built-in multidimensional array type. One possible workaround here is to use a "simulated" multidimensional array (1D array of pointers to other 1D arrays; or a plain 1D array that simulates multidimensional array through index recalculation).
In C++ use std::vector to model arrays unless you have a specific reason for using an array.
Example of a 3x2 vector filled with 0's called "myArray" being initialized:
vector< vector<int> > myArray(3, vector<int>(2,0));
Passing this construct around is trivial, and you don't need to screw around with passing length (because it keeps track):
void myFunction(vector< vector<int> > &myArray) {
for(size_t x = 0;x < myArray.length();++x){
for(size_t y = 0;y < myArray[x].length();++y){
cout << myArray[x][y] << " ";
}
cout << endl;
}
}
Alternatively you can iterate over it with iterators:
void myFunction(vector< vector<int> > &myArray) {
for(vector< vector<int> >::iterator x = myArray.begin();x != myArray.end();++x){
for(vector<int>::iterator y = x->begin();y != x->end();++y){
cout << *y << " ";
}
cout << endl;
}
}
In C++0x you can use the auto keyword to clean up the vector iterator solution:
void myFunction(vector< vector<int> > &myArray) {
for(auto x = myArray.begin();x != myArray.end();++x){
for(auto y = x->begin();y != x->end();++y){
cout << *y << " ";
}
cout << endl;
}
}
And in c++0x for_each becomes viable with lambdas
void myFunction(vector< vector<int> > &myArray) {
for_each(myArray.begin(), myArray.end(), [](const vector<int> &x){
for_each(x->begin(), x->end(), [](int value){
cout << value << " ";
});
cout << endl;
});
}
Or a range based for loop in c++0x:
void myFunction(vector< vector<int> > &myArray) {
for(auto x : myArray){
for(auto y : *x){
cout << *y << " ";
}
cout << endl;
}
}
*I am not near a compiler right now and have not tested these, please feel free to correct my examples.
If you know the size of the array at compile time you can do the following (assuming the size is [x][10]):
MyFunction(int myArray[][10])
If you need to pass in a variable length array (dynamically allocated or possibly just a function which needs to take different sizes of arrays) then you need to deal with pointers.
And as the comments to this answer state:
boost::multiarray may be appropriate since it more efficiently models a multidimensional array. A vector of vectors can have performance implications in critical path code, but in typical cases you will probably not notice an issue.
Pass it as a pointer, and take the dimension(s) as an argument.
void foo(int *array, int width, int height) {
// initialize xPos and yPos
assert(xPos >= 0 && xPos < width);
assert(yPos >= 0 && yPos < height);
int value = array[yPos * width + xPos];
}
This is assuming you have a simple two-dimensional array, like int x[50][50].
There are already a set of answers with the most of the common suggestions: using std::vector, implementing a matrix class, providing the size of the array in the function argument... I am only going to add yet another solution based on native arrays --note that if possible you should use a higher level abstraction.
At any rate:
template <std::size_t rows, std::size_t cols>
void function( int (&array)[rows][cols] )
{
// ...
}
This solution uses a reference to the array (note the & and the set of parenthesis around array) instead of using the pass-by-value syntax. This forces the compiler not to decay the array into a pointer. Then the two sizes (which could have been provided as compile time constants can be defined as template arguments and the compiler will deduct the sizes for you.
NOTE: You mention in the question that the sizes are actually static constants you should be able to use them in the function signature if you provide the value in the class declaration:
struct test {
static const int rows = 25;
static const int cols = 80;
};
void function( int *array[80], int rows ) {
// ...
}
Notice that in the signature I prefer to change the double dimension array for a pointer to an array. The reason is that this is what the compiler interprets either way, and this way it is clear that there is no guarantee that the caller of the function will pass an array of exactly 25 lines (the compiler will not enforce it), and it is thus apparent the need for the second integer argument where the caller passes the number of rows.
You can't pass an arbitrary size like that; the compiler doesn't know how to generate the pointer arithmetic. You could do something like:
MyFunction(int myArray[][N])
or you could do:
MyFunction(int *p, int M, int N)
but you'll have to take the address of the first element when you call it (i.e. MyFunction(&arr[0][0], M, N).
You can get round all of these problems in C++ by using a container class; std::vector would be a good place to start.
The compiler is complaining because it needs to know the size of the all but the first dimension to be able to address an element in the array. For instance, in the following code:
int array[M][N];
// ...
array[i][j] = 0;
To address the element, the compiler generates something like the following:
*(array+(i*N+j)) = 0;
Therefore, you need to re-write your signature like this:
MyFunction(int array[][N])
in which case you will be stuck with a fixed dimension, or go with a more general solution such as a (custom) dynamic 2D array class or a vector<vector<int> >.
Use a vector<vector<int> > (this would be cheating if underlying storage was not guaranteed to be contiguous).
Use a pointer to element-of-array (int*) and a size (M*N) parameter. Here be dragons.
First, lets see why compiler is complaining.
If an array is defined as int arr[ ROWS ][ COLS ]; then any array notation arr[ i ][ j ] can be translated to pointer notation as
*( arr + i * COLS + j )
Observe that the expression requires only COLS, it does not require ROWS. So, the array definition can be written equivalently as
int arr [][ COLS ];
But, missing the second dimension is not acceptable. For little more details, read here.
Now, on your question:
Is there a way to rewrite the
parameter list so that I can pass an
array with any size to the function?
Yes, perhaps you can use a pointer, e.g. MyFunction( int * arr );. But, think about it, how would MyFunction() know where to stop accessing the array? To solve that you would need another parameter for the length of the array, e.g. MyFunction( int * arr, size_t arrSize );
Yes: MyFunction(int **myArray);
Careful, though. You'd better know what you're doing. This will only accept an array of int pointers.
Since you're trying to pass an array of arrays, you'll need a constant expression as one of the dimentions:
MyFunction(int myArray[][COLS]);
You'll need to have COLS at compile time.
I suggest using a vector instead.
Pass a pointer and do the indexing yourself or use a Matrix class instead.
yes - just pass it as pointer(s):
MyFunction(int** someArray)
The downside is that you'll probably need to pas the array's lengths as well
Use MyFunction(int *myArray[])
If you use MyFunction(int **myArray) an pass int someArray[X][Y], the program will crash.
EDIT: Don't use the first line, it's explained in comments.
I don't know about C++, but the C99 standard introduced variable length arrays.
So this would work in a compiler that supports C99:
void func(int rows, int cols, double[rows][cols] matrix) {
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
printf("%f", matrix[r][c]);
}
}
}
Note that the size arguments come before the array. Really, only the number of columns has to be known at compile time, so this would be valid as well:
void func(int rows, int cols, double[][cols] matrix)
For three or more dimensions, all but the first dimension must have known sizes. The answer ArunSaha linked to explains why.
Honestly, I don't know whether C++ supports variable-length arrays, so this may or may not work. In either case, you may also consider encapsulating your array in some sort of matrix class.
EDIT: From your edit, it looks like C++ may not support this feature. A matrix class is probably the way to go. (Or std::vector if you don't mind that the memory may not be allocated contiguously.)
Don't pass an array, which is an implementation detail. Pass the Board
MyFunction(Board theBoard)
{
...
}
in reality my array's size is defined by two static const ints in a class, but the compiler won't accept something like MyFunction(int myArray[Board::ROWS][Board::COLS]).
That's strange, it works perfectly fine for me:
struct Board
{
static const int ROWS = 6;
static const int COLS = 7;
};
void MyFunction(int myArray[Board::ROWS][Board::COLS])
{
}
Maybe ROWS and COLS are private? Can you show us some code?
In C++, using the inbuilt array types is instant fail. You could use a boost::/std:: array of arrays or vector of arrays. Primitive arrays are not up to any sort of real use
In C++0x, you can use std::initializer_list<...> to accomplish this:
MyFunction(std::initializer_list<std::initializer_list<int>> myArray);
and use it (I presume) like this (with the range based for syntax):
for (const std::initializer_list<int> &subArray: myArray)
{
for (int value: subArray)
{
// fun with value!
}
}

C++ class for arrays with arbitrary indices

Do any of the popular C++ libraries have a class (or classes) that allow the developer to use arrays with arbitrary indices without sacrificing speed ?
To give this question more concrete form, I would like the possibility to write code similar to the below:
//An array with indices in [-5,6)
ArbitraryIndicesArray<int> a = ArbitraryIndicesArray<int>(-5,6);
for(int index = -5;index < 6;++index)
{
a[index] = index;
}
Really you should be using a vector with an offset. Or even an array with an offset. The extra addition or subtraction isn't going to make any difference to the speed of execution of the program.
If you want something with the exact same speed as a default C array, you can apply the offset to the array pointer:
int* a = new int[10];
a = a + 5;
a[-1] = 1;
However, it is not recommended. If you really want to do that you should create a wrapper class with inline functions that hides the horrible code. You maintain the speed of the C code but end up with the ability to add more error checking.
As mentioned in the comments, after altering the array pointer, you cannot then delete using that pointer. You must reset it to the actual start of the array. The alternative is you always keep the pointer to the start but work with another modified pointer.
//resetting the array by adding the offset (of -5)
delete [] (a - 5);
A std::vector<int> would do the trick here.
Random acess to a single element in a vector is only O(1).
If you really need the custom indices you can make your own small class based on a vector to apply an ofset.
Use the map class from the STL:
std::map<int, int> a;
for( int index = -5; index < 6; ++index )
{
a[index] = index;
}
map is implemented internally as a sorted container, which uses a binary search to locate items.
[This is an old thread but for reference sake...]
Boost.MultiArray has an extents system for setting any index range.
The arrays in the ObjexxFCL library have full support for arbitrary index ranges.
These are both multi-dimensional array libraries. For the OP 1D array needs the std::vector wrapper above should suffice.
Answer edited because I'm not very smart.
Wrap an std::vector and an offset into a class and provide an operator[]:
template <class T>
class ArbVector
{
private:
int _offset;
std::vector<T> container;
public:
ArbVector(int offset) : _offset(offset) {}
T& operator[](int n) { return container[n + _offset] }
};
Not sure if this compiles, but you get the idea.
Do NOT derive from std::vector though, see comments.