to pass RAII structure as 2D-array into a function - c++

There is a function, accepting 2D-array:
void foo ( double ** p )
{ /*writing some data into p*/ }
I wouldn't like to pass raw 2D array into this function because i don't want to manage memory calling new and delete. Also i wouldn't like to change function signature to void foo ( std::vector< std::vector<double> >& ). And i can't make foo as a template function (in my project it's a COM-interface method).
I would like to pass some RAII object decoring it raw-one, like
void foo ( double * p ){}
std::vectore<double> v(10);
p( &v[0] );
Is there way to do this for 2D-arrays? I tried
std::vector< std::vector<int> > v;
foo( &v[0][0] )
and
std::vector< std::tr1::shared_ptr<int> > v;
but i get compile errors error C2664 - cannot convert parameter.
Also, can one be sure that raw address arithmetics inside the function works ok in this case?
No C++11, the sizes of 2D-array are known.

One possible solution is to change:
std::vector< std::vector<int> > v;
foo( &v[0][0] )
to
std::vector< std::vector<int> > v;
std::vector<int*> v_ptr;
for (...) {
v_ptr[i] = &v[i][0];
}
foo( &v_ptr[0])

Although Andreas already gave an answer to your question that solves your particular problem, I would like to point out, that although that works, it is probably not what you want to do.
As you are using C++ (and not an easier to use language), I am assuming that you care about performance. In that case your approach is in all likelihood wrong from the beginning, as double** represents an array of arrays (or rather can represent) and not a 2D array. Why is this bad? Because, just as with the std::vector< std::vector<int> > example, multiple allocations are required, and the resulting memory is non-contiguous (which is bad for the cache) unlike a double array[N][M].
For 2D arrays you should in fact use 1D arrays with index calculation, which is far more cache-friendly. This of course does not allow [x][y]-style indexing (instead you have to use [x+N*y] or [y+M*x], depending on your choice of "Fortran order" or "C order"), but avoids cache issues and only requires a single allocation (and a simple double*pointer).
If you are iterating all elements of the array as in
for(unsigned x = 0; x < N; ++x) for(unsigned y = 0; y < M; ++y)
{
unsigned idx = y + M * x;
p[idx] = bar(x, y); // equivalent to p[x][y] = bar(x,y) in the array-of-arrays case
}
You can even avoid the multiplications as this is basically just a 1D iteration with additional generation of 2D indices
for(unsigned x = 0, idx = 0; x < N; ++x) for(unsigned y = 0; y < M; ++y, ++idx)
{
p[idx] = bar(x, y);
}

Related

Return a 2D array from a function with just the array size as the arguments

i am new to c++ and i am trying to create an Array from within a function with just the array size, [row][col], as the argument. I know you cannot return an array from a function in c++. I would allocate memory in these situations if i were to code in C. However, i am not sure what is the C++ way (:
I tried,
int** get2Darray(int row, int col){
int** randInts = new int[row][col]; //Invalid. Constant required.
return randInts;
}
Thanks.
EDIT: vector class does the trick, however, my program is heavily modular. I dont have access to the main program. My function should be called and a fresh array should be created and returned. Implementation should only be done inside this function
Either change int** randInts = new int[row][col]; into int* randInts = new int[row * col]; or define int** randInts as follows:
int** randInts = new int*[row];
for (int i = 0; i < row; ++i) {
randInts[i] = new int[col];
}
It's a C way, not a C++ way. In C++ you should use containers (e.g. a vector as suggested in the comments).
I have shown this using vector <vector<T> >, but you can also use Eigen matrix or boost::ublas::matrix
std::vector< std::vector<int> > foo(const int rows, const int cols)
{
std::vector< std::vector<int> > v;
v.resize(rows);
for (auto i = 0; i < rows; i++)
{
v[i].resize(cols);
}
return v;
}
This will return a matrix of desired dimensions, and all elements will be initialized to 0.
The std::move part invokes a behavior called move semantics. You can read up on it. It's basically a better way of returning objects across a function boundary.
For compatibility's sake, if you must have a native array, then do this :
std::vector< vector<int> > temp = foo(rows, cols);
int *v = &temp[0][0];
Now, you can implement the gymnastics to get the correct index inside of int *v. You don't need multiple indirection.
P.S. This implementation assumes that your compiler supports C++ 11.

What is the equivalent matrix-like C-array of a nested std::vector (for C and C++ interop)?

What is the equivalent matrix-like C-array of a nested std::vector (for C and C++ interop)?
For example, if one wanted to treat std::vector<std::vector<int>> as some kind of int arr[n][m], where n is the dimension of the outer vector and m of the inner vector, then what structure would one use in C?
This is motivated by wanting to have a similar correspondence between matrices in C and C++ as for vectors in:
https://stackoverflow.com/a/1733150/4959635
Based on additional information in the comments, let me suggest you do something like this instead:
class TwoDimVector {
public:
TwoDimVector(int num_cols, int num_rows)
: m_num_cols(num_cols)
, m_num_rows(num_rows)
, m_data(m_num_cols * m_num_rows, 0)
{ }
int & ix(int row, int col) {
return data[num_cols * row + col];
}
const int m_num_rows;
const int m_num_cols;
private:
std::vector<int> m_data;
}
When you do nested vectors, there's a lot of extra work happening. Also, with nested vectors, the data is not contiguous, making it hard to work with any C-apis. Notice with this data structure, the size is fixed at construction time and accessible. This is designed to be row contiguous, so for C interoperability you can access extra raw pointers like so:
TwoDimVector tdv(4,3);
int * raw = &tdv.ix(0,0);
int * raw_second_row = &tdv.ix(1,0);
Just note: if you pass this into a function, be sure to pass by reference:
void do_work(TwoDimVector & tdv) {
...
}
If you don't pass by reference, it will copy everything, which is a bunch of (typically unnecessary) work.
Maybe, this code
void translate(const vector< vector >& vec){
int m = vec.size(), n = 0;
for (vector<int>& deep : vec) // search maximum size if nested vectors
{
if (deep.size() > n)
n = deep.size();
}
int arr[m][n];
m = n = 0;
for (vector<int>& deep : vec){
for (int& x : deep)
{
arr[m][n] = x;
++n;
}
++m;
}
// So, I really don't know how you can return this array :(
}
You see, it code is BAD, you mustn't do it !!!
If you writing on C++ you should using std::vector - it is easier.
C-like arrays is heritage from C, you shouldn't using they

How to solve the error "expression must be a modifiable lvalue" in c++?

const int ADJ_MATRIX[VERTEX_NUM][VERTEX_NUM]={
{0,1,1,0,0,0,0,0},
{1,0,0,1,1,0,0,0},
{1,0,0,0,0,1,1,0},
{0,1,0,0,0,0,0,1},
{0,1,0,0,0,0,0,1},
{0,0,1,0,0,0,1,0},
{0,0,1,0,0,1,0,0},
{0,0,0,1,1,0,0,0}
};
typedef struct {
int vertex;
int matrix[VERTEX_NUM][VERTEX_NUM];
int vNum;
int eNum;
}Graph;
void buildGraph(Graph *graph){
graph->vNum = VERTEX_NUM;
graph->eNum = EDGE_NUM;
graph->matrix = ADJ_MATRIX;
}
The error occurs in this sentence:
graph->matrix = ADJ_MATRIX;
I am new to c++. please tell me why this problem occur and how to solve it?
I want to assign ADJ_MATRIX to the matrix in struct.
As was said, you can't assign arrays in C++. This is due to the compiler being a meanie, because the compiler can. It just won't let you do it...
... unless you trick it ;)
template <typename T, int N>
struct square_matrix {
T data[N][N];
};
square_matrix<int, 10> a;
square_matrix<int, 10> b;
a = b; // fine, and actually assigns the .data arrays
a.data = b.data; // not allowed, compiler won't let you assign arrays
The catch? Now the code needs some little things:
const square_matrix<int, VERTEX_NUM> ADJ_MATRIX={{
// blah blah
}}; // extra set of braces
typedef struct {
int vertex;
square_matrix<int, VERTEX_NUM> matrix;
int vNum;
int eNum;
}Graph;
void buildGraph(Graph *graph){
graph->vNum = VERTEX_NUM;
graph->eNum = EDGE_NUM;
graph->matrix = ADJ_MATRIX; // no change
}
And to access the cells, now we need to use graph->matrix.data[1][2]. This can be mitigated by overloading operator[] or operator() for square_matrix. However, this is now getting terribly close to the new std::array class, or the Boost equivalent boost::array, so it might be wise to consider those instead.
Unfortunately (or maybe fortunately, who knows...) you can't just assign one array to another in C++.
If you want to copy an array, you will need to either copy each of it's elements into a new array one by one, or use the memcpy() function:
for( int i = 0; i < VERTEX_NUM; i++ )
for( int j = 0; j < VERTEX_NUM; j++ )
graph->matrix[i][j] = ADJ_MATRIX[i][j];
or
memcpy( graph->matrix, ADJ_MATRIX, VERTEX_NUM * VERTEX_NUM * sizeof(int) );
Arrays are not assignable. You can use memcpy:
memcpy(graph->matrix, ADJ_MATRIX, sizeof(graph->matrix));
You cannot assign an array to another array. You will need to copy the elements from the source to the destination index by index, or use memcpy to copy the data. Array assignment like this is not allowed
You are trying to assign your variable address of a constant data,
try using
memcpy(graph->matrix,ADJ_MATRIX,sizeof(ADJ_MATRIX));//using sizeof(graph->matrix) is safer.
You can't use an array in assignments. You may use cycles or memcpy instead
memcpy(graph->matrix, ADJ_MATRIX, VERTEX_NUM * VERTEX_NUM * sizeof(int));
or
for(int i = 0; i < VERTEX_NUM; ++i){
for(int j = 0; j < VERTEX_NUM; ++j){
graph->matrix[i][j] = ADJ_MATRIX[i][j];
}
}
The error is thrown, because int matrix[VERTEX_NUM][VERTEX_NUM] in a structure definition means that each structure will have a 2D array of integers of the predefined size and matrix is going to be pointing to its first element. The thing is that matrix cannot be assigned to an arbitrary address, because it's a const pointer i.e. its value (the address it's pointing to) cannot change.
You have 2 options here: you can either use memcpy or some stl algorithms to copy the ADJ_MATRIX into matrix directly or you can declare matrix as a pointer and do the assignment that is currently produces an error.
The latter can be done in the following way:
typedef struct {
int vertex;
const int (*matrix)[VERTEX_NUM];
int vNum;
int eNum;
}Graph;
Thus you can do graph->matrix = ADJ_MATRIX assignment, but you won't be able to modify the individual items in matrix due to constness. This means, graph->matrix[0][1] = 3; is not allowed, while you can read the elements freely.

How to return an array in c++

How should I return an array from a function? My code is
float ClassArray::arr_sub(float a[100][100], float b[100][100]) {
int i,j;
for(i = 1; i < 10; i++) {
for(j = 1; j < 10; j++){
f[i][j]=b[i][j]-a[i][j];
}
}
return f;
}
and the f returned from this function should be assigned to another array g declared in some other class.
float g[100][100];
g= cm.arr_sub(T,W);
but while building the classes, it says incompatible type assignment of float to float[100][100].
My answer here to another question on arrays explains why you don't want to use arrays.
As I say in that answer you can't assign an array like you're trying:
float g[100];
g = foo(); // illegal, assigning to arrays is not allowed
Another of the weird restrictions on arrays is that you're not allowed to return them from functions:
float foo()[100]; // illegal, returning an array from a function is not allowed
Also note that when you declare a function like float arr_sub(float a[100][100]) you might think you're passing an array by value, but in fact that invokes another of the weird exceptions made for arrays. In C and C++, whenever you declare a formal parameter of a function to be an array, the type is adjusted from 'array' to 'pointer to the array's element type'.
Since arrays don't behave like they ought, you should instead use std::array or std::vector:
std::array<float,100> foo(); // works
std::array<float,100> g;
g = foo(); // works
To do multi-dimentional arrays you can use:
std::array<std::array<float,100>,100> g;
Though that's a bit cumbersome so you can typedef it:
typedef std::array<std::array<float,100>,100> Matrix;
Matrix ClassArray::arr_sub(Matrix a, Matrix b) {
...
}
Matrix g;
g = cm.arr_sub(T,W);
And if you have a compiler that supports C++11 you can even do a template type alias:
template<typename T,int Rows,int Columns>
using Matrix2d = std::array<std::array<T,Columns>,Rows>;
Matrix2d<float,100,100> g;
Note on performance
There is one reason you might not want to return an std::array by value. If the array is large then there may be a signficant performance cost in copying the data from the return value into the variable you assign it to. If that ever proves to be a problem for you, then the solution with std::array is the same as it would be for other large types; use an 'out' parameter instead of returning by value.
void arr_sub(Matrix a, Matrix b, Matrix &result);
Matrix g;
arr_sub(T,W,g);
This doesn't apply to std::vector because std::vector can take advantage of move semantics to avoid having to copy all its elements.
If you insist on using "plain C" 2D arrays, the best thing is to pass a pointer to the result along with the two input parameters, rather than passing the arrays by value the way you did.
However, the best thing to do in C++ is to use vector<vector<float> > instead, and pass it by reference.
void ClassArray::arr_sub(
const vector<vector<float> > &a
, const vector<vector<float> > &b
, vector<vector<float> > &res)
{
for(int i=0 ; i != a.size() ; i++)
for(int j=0 ; j != b.size() ; j++)
res[i][j] = b[i][j] - a[i][j];
}
void main() {
vector<vector<float> > a(100, vector<float>(100, 12.345));
vector<vector<float> > b(100, vector<float>(100, 98.765));
vector<vector<float> > res(100, vector<float>(100, 0));
arr_sub(a, b, res);
}
The best way to do this is to wrap everything into a class. From the look of things, its a Matrix.
There are probably a hundred Matrix classes out there already, so it is really pointless to write another one.
But, if this is a learning exercise it might be worthwhile.
To answer your asked question, make a third argument to your function: float result[100][100]. Inside your function, write the results into the result array.
This works because in C and C++, arrays are always passed by reference and never by value. This is because C++ passes only the pointer to the beginning of the array.
if you really wish to return an array and some how manage to use it in the main(), the most efficient way would be to declare the returning array as dynamic. that way you will avoid losing the pointer to this new array as it will be allocated in heap and not in stack.

Multi-dimensional vector initialization

I have following std::vector declaration:
std::vector<std::vector<std::vector<int> > > m_input;
I am initializing it as follows:
m_input.resize (100);
m_output.resize(100);
for (int i = 0; i < 100; ++i) {
m_input [i].resize(100);
m_output[i].resize(100);
for (int j = 0; j < 100; ++j){
m_input [i][j].resize(100);
m_output[i][j].resize(100);
}
}
How can I achieve this via the member initializer list?
std::vector<T> has a constructor that takes two arguments, a number of elements and an initial value. In your case, you want to initialize m_input with 100 copies of a std::vector<std::vector<int> > , so it'd be : m_input(100, X). Now, that X in turn is a vector of 100 std::vector<int>, which in turn contains a hundred ints:
: m_input(100, std::vector<std::vector<int> >(100, std::vector<int>(100, 0)))
my_class::my_class()
: m_input(100, std::vector< std::vector<int> >(100, std::vector<int>(100) ))
{
}
That said, implementing a multi-dimensional field should be done by projecting into a one-dimensional one, as Viktor said in his comment to the question.
If you can assert that your vector dimensions are going to be of a fixed length, then why not use std::array?
For example:
std:array<std::array<std::array<int, 100>, 100>, 100>
That way you can take advantage of all the memory being contiguously allocated (as hinted at by Viktor_Sehr in the comments), without the added implementation woes of accessing a 1-dimensional array in a 3-dimensional way.