Accessing vector<vector<int>> elements - c++

I have defined:
const vector<vector<int>> *ElementLines::Quad4 = new vector<vector<int>>
{
{ 0, 1 },
{ 1, 2 },
{ 2, 3 },
{ 3, 0 }
};
Later on, I want to iterate over that collection, to which an object is pointing:
for (int j = 0; j < e->LinesIndices->size(); j++)
{
int n1Index = e->LinesIndices[j][0]; //I expect 0 (for j = 0)
int n2Index = e->LinesIndices[j][1]; //I expect 1 (for j= 0)
}
The code above won't compile:
no suitable conversion function from "const std::vector<int, std::allocator<int>>" to "int" exists
But if I add LinesIndices[j][0][0] it indeed delivers an int. I don't quite understand what is happening here. To access a vector I just use one pair of square brackets [i], is it different for this nested vector of vectors? (I would expect to be able accessing the contents by using two pairs of square brackets).

Your code is not compiling because your e->LinesIndices is a vector<vector<int>>* (i.e. a pointer).
In C++, as in C, you can use array notation on pointers—a[index] is equivalent to *(a + index). If your pointer pointed to the first element of an array, that is exactly how you would use that array. Unfortunately for you, you only have a single vector allocated via new. Accessing that pointer via e->LinesIndices[j] is a Very Bad Thing if j is not 0 (because you access a vector where there is no actual vector).
There is two ways to fix this. If you really want to keep your vector on the heap, allocated via new (I hope you delete it at some point!), you could dereference the pointer before accessing it:
for (int j = 0; j < e->LinesIndices->size(); j++)
{
int n1Index = (*e->LinesIndices)[j][0];
int n2Index = e->LinesIndices[0][j][1]; // This would work too, but I wouldn't recommend it
}
However, the data in your vector is already on the heap. Allocating a std::vector via new is something that is—in my personal experience—very rarely necessary, and if it is not necessary for you to have a pointer here (which will heavily depend on the context you use it in), I would suggest directly creating the vector (with no pointer). If you choose this method, you will need to use e->LinesIndices.size() instead of e->LinesIndices->size().

Related

Dynamic 2D array without using new

I've been posed with creating a dynamic 2D array in C++ without using new in C++. I have been trying for a while to make something work but I'm clueless as to what I'm supposed to do.
Edit: Sorry, should have been more specific. Just to be transparent, yes it is homework, and no I don't want it solved I just want to be pointed (no pun intended) in the right direction to code it myself.
The order, for reference, is as follow: Develop a console application to create a type int matrix of size m x n using pointers. The user must input the values for the size of the matrix from the keyboard and its contents must be randomly generated (1 - 100). Then, the transpose of the matrix must be calculated and shown (it's necessary to create classes).
We can't use new, nor vector, as we have to do it just via pointers with uni-dimensional arrays. So far I created a class that represent the "rows", and another class which represents the "columns". The columns go into the rows and the rows go into another class called matrix. That was the idea but was having trouble implementing it.
new is the only way to create dynamic objects or arrays in standard C++. So, depending on how you interpret the task, it could be considered impossible.
If we assume that it is OK for you to call a standard function that internally calls new, then the problem is solvable. A commonly used way to create a dynamic array in C++ is to use std::vector. Elements of std::vector may not be arrays however, so a 2D dynamic array is not technically possible using it. One workaround is to wrap the array within a class, and use the class as element of the vector. There is a standard template for such array wrapper: std::array. An example of a vector of array wrappers:
std::vector<std::array<type_of_element, 10>> name_of_vector(number_of_arrays);
The elements of the arrays within the dynamic array managed by the vector will have effectively the same layout as a 2D array would.
malloc did the trick. Here is the code I used to test it. It was a bit convoluted to figure out how to write the matrix loop but once I got it down I realized how obvious it was.
Matriz::Matriz(int numFil, int numCol)
:numFil(numFil), numCol(numCol)
{
mat = (int *)malloc(numFil * numCol * sizeof (int));
int c = 0;
for(int i = 0; i < numFil; i++)
{
for(int j = 0; j < numCol; j++)
{
*(mat + i * numCol + j) = ++c;
}
}
}
void Matriz::printMat()
{
for(int i = 0; i < numFil; i++)
{
for(int j = 0; j < numCol; j++)
{
std::cout << *(mat + i*numCol + j);
}
std::cout << std::endl;
}
}

How to copy-by-value (not by reference) a CPLEX IloArray, the easy way

I work with CPLEX and C++ via Concert Technology and a recurrent issue I am encountering is that internally the IloArray structures seem to be overloaded vector structures with copy-by-reference operators. Which I must acknowledge is a quite neat and memory efficient way of handling the array structures.
Yet... This implies that making IloIntArray Array_copy = Array, for a previously declared and initialized IloIntArray Array, will make a reference copy of Array into Array_copy. Hence, any change in Array is automatically transferred to Array_copy. The same applies to multi-dimensional IloArray structures via the add() routine.
Let us say, for instance, that I need to populate a 2D IloArray<IloIntArray> Array2D(env), inside a for-loop indexed in i = 1 to iSize, storing in each position of Array2D[i], from i = 1 to iSize, the values of Array which will be different at each iteration of the loop. Making either:
Array2D[i].add(Array) or,
Array2D[i] = Array, assuming Array2D i-dimension was initially set to be of size iSize.
Fails to make the intended copy-by-value, since each time, a copy-by-reference is made to the elements of the i-dimension and you end up with all identical elements, equal to the last value of Array.
Now, besides, making my own copy-by-value operator constructor (Option I) or a copy routine (Option II) receiving, both, the origin and destination arrays as well as the position of the destination array (e.g. multi-dimensional array) where the origin array is to be copied.
Is there another way to make the copy-by-value? In any case, can you help me decide which one of these options is more neat and/or memory efficient? Intuitively I deem Option I to be the more efficient, but I don't know how to do it...
Thanks in advance for your help
Y
So far, I am solving my own issue by implementing a copy() function.
I have typedefed my multi-dimensional arrays as follows:
typedef IloArray<IloIntArray> Ilo2IntArray; and typedef IloArray<IloNumArray> Ilo2NumArray and so on for three or four dimensional integer or numeric arrays.
An example of my Ilo3IntArray copy(Ilo3IntArray origin) overload of the copy function I am using as a patch to make copy-by-value copies, is as follows:
Ilo3IntArray copy(Ilo3IntArray origin) {
IloInt iSize = origin.getSize();
Ilo3IntArray destination(env, iSize);
IloInt jSize = origin[0].getSize();
IloInt zSize = origin[0][0].getSize();
for (IloInt i = 0; i < iSize; i++) {
destination[i] = Ilo2IntArray(env, jSize);
for (IloInt j = 0; j < jSize; j++) {
destination[i][j] = IloIntArray(env, zSize);
for (IloInt z = 0; z < zSize; z++) {
destination[i][j][z] = origin[i][j][z];
}
}
}
return destination;
// Freeing Local Memory
destination.end();
}
Your comments and/or better answers are welcome!!!

proper memory allocation for a 2D array in a class in C++

I am writing a C++ class that uses some fixed arrays, as well as some dynamically allocated arrays.
I was wondering if anybody can guide me for the proper way to allocate memory for the dynamic arrays , probably in the constructor/deconstructor, and also if I need to explicitly call them to make sure I don't get a seg fault.
Here is a simplified version of the related part of my code:
class Network {
public:
int n_nodes;
int user_index[MAX_USERS]; //a fixed array
int adjacency_matrix[][MAX_ITEMS];
//Network(int n_node, int** adjacency); //I would rather to set the element s in a function other than the constructor
Initializer(int n_node, int** adjacency);
~Netowrk();
}
So here are my specific question for this class:
1 - Can I have the 2D array adjacency_matrix[][] with undecided number of rows and columns until it's set by the user in the initializer function?
2 - where should I delete the 2D array? should I write it in the deconstructor? Should I call the deconstructor explicitly? Is there anything else I need to destroy in the deconstructor?
1 - Can I have the 2D array adjacency_matrix[][] with undecided number of rows and columns until it's set by the user in the initializer function?
Yes. The best way to do this, however, is not to use arrays at all. Instead, use std::vector, which manages the memory for you. There are two ways that you can do this. If you actually want to be able to use the [row][column] syntax to access elements, you'll need to use two dimensions of std::vectors:
std::vector<std::vector<int> > adjacency_matrix;
Once you know the dimensions, you can populate it:
adjacency_matrix.assign(rows, std::vector<int>(columns));
It is often easier to use a single-dimensional array (or a std::vector<int>) containing all of the elements and use row * row_count + column to access the element at index (row, column). This way, there are fewer dynamic allocations. You can wrap up the logic of accessing elements into a couple of helper functions.
2 - where should I delete the 2D array? should I write it in the deconstructor?
You don't have to delete anything if you use a std::vector. It cleans itself up.
Should I call the [destructor] explicitly?
No.
Is there anything else I need to destroy in the [destructor]?
Ideally, no. If you use the Standard Library containers, like std::vector and smart pointers, you shouldn't have to clean anything up. You should avoid trying to manage resources on your own in C++: there are library facilities to do this tedious task for you and you should take advantage of them.
1 - Can I have the 2D array adjacency_matrix[][] with undecided number of rows and columns until it's set by the user in the initializer function?
Yes you can. For example:
int* adjacency_matrix_;
int* getAdjacency(int i, int j)
{
if (!adjacency_matrix_)
return 0;
else
return adjacency_matrix_ + i*n_nodes + j;
}
Network()
: n_nodes(0),
adjacency_matrix_(0)
{}
void Initializer(int n_node, int** adjacency)
{
adjacency_matrix_ = new int[n_nodes * n_nodes];
// Copy over data.
}
As to whether you should, that depends on whether you have a reason for not using std::vector<>.
2 - where should I delete the 2D array? should I write it in the deconstructor?
Should I call the deconstructor explicitly?
Is there anything else I need to destroy in the deconstructor?
Yes, definitely free in the destructor using array operator delete:
~Network()
{
delete [] adjacency_matrix_;
}
No, your destructor will be called whenever the Network object itself goes out of scope. It is (very) rarely necessary to make an explicit destructor call.
No, all a destructor needs to explicitly release is whatever your explicitly acquire.
You may like the example matrix class I wrote in an answer to another question
The question itself was about good C++ design practices, but the chosen example was a multi-dimensional array.
There are several ways to do this.
The easiest way is to use vectors, and if you don't like to manage your own memory, this is perfect for you. However, because I like to manage my own memory, and I have found this method to be slow and cumbersome at times, I have learned of other ways.
The fastest way is to allocated a one dimensional array and treat it as you would a two dimensional array. Here is an example:
int *array = new int[width*height];
int get_array(int column, int row)
{
return array[row*width + column];
}
delete [] array;
This can be generalized to the nth-dimension:
int *array = new int[w1*w2*...*wn];
int get_array(int i1, int i2, ..., int in)
{
return array[in*(w1*w2*...*w(n-1)) + i(n-1)*(w1*w2*...*w(n-2)) + ... + i2*w1 + i1];
}
delete [] array;
If you want to be able to have different widths for each row, then you can make an array of pointers. This solution is slow to initialize and clean up, but flexible, tunable, and has relatively fast execution time. It can also be extremely dangerous if you make a mistake though.
int **array = new int*[height];
for (int i = 0; i < height; i++)
array[i] = new int[width(i)];
at which point, to access it, all you have to do is the customary
array[i][j]
however, to free this array you have to do it row by row
for (int i = 0; i < height; i++)
delete [] array[i];
delete [] array;
This can also generalize to the nth dimension.
int **....*array = new int**...*[w1];
for (int i1 = 0; i1 < w1; i1++)
{
array[i1] = new int**..*[w2];
for (int i2 = 0; i2 < w2; i2++)
{
array[i1][i2] = new int**.*[w3];
...
for (int in = 0; in < wn; in++)
array[i1][i2]...[in] = new int[wn];
}
}
for (int i1 = 0; i1 < w1; i1++)
{
for (int i2 = 0; i2 < w2; i2++)
{
...
for (int in = 0; in < wn; in++)
delete [] array[i1][i2]...[in];
...
delete [] array[i1][i2];
}
delete [] array[i1];
}
delete [] array;
This kind of setup tends to wreak havoc on memory. Just a two dimensional array of these would result in width+1 separate arrays to be malloc-ed. It would be faster to just malloc one big array and figure out the indices yourself.

How do you delete (or fill with specific values) a static n-dimension array?

const int ROWS = 3;
const int COLUMNS = 4;
void fillArray(double a[ROWS][COLUMNS], double value);
void deleteArray(double a[ROWS][COLUMNS]);
int main () {
double a[ROWS][COLUMNS];
fillArray(a, 0);
deleteArray(a);
}
In C++, how do you delete (or fill with specific values) a static n-dimension array?
In C++ we generally do not use arrays. We use std::vector.
You can use memset or std::fill to fill the array with specific values.
BTW you can use delete on dynamically allocated arrays not on static ones.
memset( a, 0 ,ROWS * COLUMNS * sizeof( double ));
or
std::fill(&a[0][0], &a[0][0]+sizeof(a)/sizeof(double), 0);
You can delete only an object created by new (and that object will be allocated in the heap). What do you mean by "deleting a static POD variable"? It has no sense:
1) It doesn't have any destructor to perform additional tasks before freeing the memory,
2) The stack memory will be "freed" as you exit the current block.
And to set it: either loop, either simple memset(a, 0, sizeof(a)); .
Also, the array in your example is not static.
std::vector is what is generally used for C++ arrays (especially when you're new at it). One of vector's constructors will fill it for you to:
std::vector<type> myVector(initialSize, defaultValue);
If you want multidimensional, you could do a vector of vectors, or boost::multi_array:
boost::multi_array<type, numberOfDimensions> myArray(boost::extents[firstSize][secondSize][thirdSize]);
In that case, you'll need to use the multiple-for-loops approach, because it doesn't seem to have a constructor that does that.
EDIT: Actually you can use std::vector to make a multidimensional array with default values:
std::vector<std::vector<double> > a(3, std::vector<double>(4, 0));
Where 3 is the number of rows, 4 is the number of columns and 0 is the default value.
What it's doing is create a vector of vectors with 3 rows, where the default value for each row is a vector with 4 zeroes.
Filling arrays in C++ is the same as filling them using C, namely nested for loops
int i, j;
for (i = 0; i < ROWS; i++)
for (j = 0; j < COLS; j++)
a[i][j] = 0
Arrays aren't "deleted" but they can use free if they've been allocated on the heap (if they've been allocated on the stack within a function, this is unnecessary).
int i;
for (i = 0; i < ROWS; i++)
free(a[i]);
free(a);
Firstly, the code you posted seems confused. What is it that you think "deleteArray" is supposed to do? 'a' is an auto variable and therefore cannot be deleted or freed.
Secondly, wrap your array in a class. There is a nice one in the FAQ that you can start with, but it can be improved. The first improvement is to use a vector rather than newing a block of memory. Then std::fill can be used to fill the array.
Use std::fill
#include <algorithm>
And then your implementation is simply:
std::fill(&a[0][0], &a[0][0]+sizeof(a)/sizeof(a[0][0], value);
You don't delete the array since it is stack allocated.

Why can't a multidimensional array be allocated with one new call in C++?

In C++ you can easily allocate one dimensional array like this:
T *array=new T[N];
And you can delete it with one statement too:
delete[] array;
The compiler will know the magic how to deallocate the correct number of bytes.
But why can't you alloc 2-dimensional arrays like this?
T *array=new T[N,M];
Or even like this?
T *array=new T[N,M,L];
If you want a multidimensional you have to do it like this:
T **array=new T*[N];
for(int i=0;i<N;i++) array[i]=new T[M];
If you want a fast program that uses matrices (matrix operations, eigenvalue algorithms, etc...) you might want to utilize the cache too for top performance and this requires the data to be in the same place. Using vector<vector<T> > is the same situation. In C you can use variable length arrays on the stack, but you can't allocate them on the heap (and stack space is quite limited), you can do variable length arrays in C++ too, but they won't be present in C++0x.
The only workaround is quite hackish and error-phrone:
T *array=new T[N*M];
for(int i=0;i<N;i++)
for(int j=0;j<M;j++)
{
T[i*N+j]=...;
}
Your workaround of doing T *array=new T[N*M]; is the closest you can get to a true multi-dimensional array. Notice that to locate the elements in this array, you need the value of M (I believe your example is wrong, it should be T[i*M+j]) which is known only at run-time.
When you allocate a 2D array at compile-time, say array[5][10], the value 10 is a constant, so the compiler simply generates code to compute i*10+j. But if you did new T[N,M], the expression i*M+j depends on the value of M at the time the array was allocated. The compiler would need some way to store the value of M along with the actual array itself, and things are only going to get messy from here. I guess this is why they decided not to include such a feature in the language.
As for your workaround, you can always make it less "hackish" by writing a wrapper class that overloads operator (), so that you could do something like array(i, j) = ....
Because multidimensional array is something different then array of arrays/pointers.
use std::vector
Why can't a multidimensional array be allocated with one new call in C++?
Because when the ISO wrote the C++ language standard, they didn't decide to add that feature to the language. I don't know why they decided not to.
If you don't like that, you can create helper functions to allocate/free multidimensional arrays, or you can switch to a language like C# or Java that does support easily allocating multidimensional arrays.
What you can do, however, is allocate an object containing a two-dimensional array off the heap. I would just write a wrapper class for it.
I was thinking about this question last night, and this solution came to me.
T * raw = new T[N*M];
T ** array = new T*[N];
for(int i=0; i<N; i++)
array[i] = raw + i * M;
Now "array" acts just like a contiguous static sized two dimensional array. You just have to take care of deleting both the raw array, and the multi-dimensional array.
I would recommend that you use a Boost::multi_array, from the library of the same name, which provides a simple interface to a multidimensional array. It can be allocated in one line, and at a sufficiently high optimization level is usually as fast as a native array.
Here's some example code from the library's website:
#include "boost/multi_array.hpp"
#include <cassert>
int
main () {
// Create a 3D array that is 3 x 4 x 2
typedef boost::multi_array<double, 3> array_type;
typedef array_type::index index;
array_type A(boost::extents[3][4][2]);
// Assign values to the elements
int values = 0;
for(index i = 0; i != 3; ++i)
for(index j = 0; j != 4; ++j)
for(index k = 0; k != 2; ++k)
A[i][j][k] = values++;
// Verify values
int verify = 0;
for(index i = 0; i != 3; ++i)
for(index j = 0; j != 4; ++j)
for(index k = 0; k != 2; ++k)
assert(A[i][j][k] == verify++);
return 0;
}
Because the comma is an operator.
int a = (3, 5, 7, 9);
The program will evaluate 3, discard the result,
evaluate 5, discard the result,
evaluate 7, discard the result,
evaluate 9, and assign it to a.
Hence the syntax you are looking for can't be use,
and retain backward compatibility to c.