reference to an array of size determined at run-time - c++

I tried to find this but can't find any. I know I can create a reference to an array variable:
int x[10] = {}; int (&y)[10] = x;
However, in the case that the array size is not known at compile time, like in the following code:
const int n = atoi( string ); //the string is read from a text file at run time.
int x[n] = {}; int (&y)[n] = x; //this generates a compiling error.
Even if int n is declared const, as long as n is not known at compile time, the reference is invalid. The compiler will say something like this: reference to type 'int [n]' cannot bind to a value of unrelated type 'int [n]'. Anyone has any idea about how to fix this? Thanks in advance.

Runtime-length arrays are a C99 feature and do not exist in standard C++. They're present as an extension on some C++ compilers, but don't mix well with C++ features, like references and templates.
You should probably use a vector.

The feature of declaring arrays dynamically like shouldn't be used in C++. Not all compilers support it. Consider using the STL containers instead. Like std::vector<int>

Related

Why should global array size be an integer constant?

In C++ I tried declaring a global array of some size. I got the error:
array bound is not an integer constant before ‘]’ token
But when I declared an array of the same type in the main() function it is working fine.
Why is there different behaviour here?
int y=5;
int arr[y]; //When I comment this line it works fine
int main()
{
int x=5;
int arr2[x]; // This line doesn't show any error.
}
Edit: Many are suggesting this question is a duplicate of Getting error "array bound is not an integer constant before ']' token". But that question doesn't answer why there is different behaviour.
Both examples are ill-formed in C++. If a compiler does not diagnose the latter, then it does not conform to the standard.
Why there is a different behaviour here?
You use a language extension that allows runtime length automatic arrays. But does not allow runtime length static arrays. Global arrays have static storage.
In case you are using GCC, you can ask it to conform to the standard by using the -pedantic command line option. It is a good idea to do so in order to be informed about portability problems.
The size of an array must be a constant. You can fix this by declaring y as const.
const int y=5;
int arr[y];
As for why this worked in main, g++ does allow a variable length array in block scope as an extension. It is not standard C++ however.
Both shouldn't be used, one works because (as #eerorika said) automatic length arrays are allowed on runtime, but global arrays need to have static storage.
If you want to declare an array with a variable size (e.g. given by std::cin) you would do something along the lines of:
int x;
std::cin >> x;
const int n = x;
float arr[n];
But you wouldn't be able to set it to contain just zeros with float arr[n] = {0} (if you need to add to a value in the array, not being sure you set it), you would need to use a loop like that
for(int i = 0; i < n; i++)
{
arr[i] = 0;
}
The type-system of C++ handles these C-like arrays in a way that it defines arr2 from your example of type int[5]. So, yes the number of elements of the array is part of the type!
This puts some constraints on what you are allowed to use in the definition of C-like arrays. I.e. this number needs to have static storage, needs to be immutable and needs to be available at compile time.
So, you might want to change your code to something like the following, which will have another goodie. It initializes the array in a proper way:
int arr2[] = {0, 0, 0, 0, 0};

Array Size Declaration issue [duplicate]

This question already has answers here:
Why aren't variable-length arrays part of the C++ standard?
(10 answers)
Closed 8 years ago.
int n=5;
int arr[n];
I want to declare size of array as above in C++, but I get error while compiling. I find a lot of code in internet which uses these type of declaration instead of simple putting int arr[5]. How come the code compiles successfully for them but not for me. P.S: I use windows7 and Visual Studio(IDE).
Error Message : Expresion must have a constant value
The number of elements of the array, the array bound, must be a constant expression.
You have to use
const int n = 5;
or
constexpr int n = 5;
else it is a non standard extension : variable length array (VLA).
The error message actually describes rather well what’s going on: C++ does not support arrays with a non-constant size (more precisely, the size needs to be known at compile time).
There are two solutions for this:
If the size is actually a constant, declare it as constexpr (if you can’t use C++11, you can also use const):
constexpr int n = 5;
std::array<int, n> arr;
Which requires the standard header <array>. Or, if you cannot use C++11, change the second line to
int arr[n];
If the size isn’t known at compile time, don’t use a static array, use a dynamic container instead:
int n = 5;
std::vector<int> arr(n);
This requires the <vector> standard header.

C++: How to get pointer to 2 dimensional dynamic array?

I looked at this excellent answer but can't figure out how to apply it to this snipped:
//this is in the .hpp file
std::atomic<int> size = 10;
std::recursive_mutex *locks[2];
//in some function of the class
//it's important that the 2nd array dimension is dynamic
the_lock[0] = new std::recursive_mutex[size];
the_lock[1] = new std::recursive_mutex[size];
std::recursive_mutex (*locks_2)[2][size] = &locks;
The assignment gives me
error: cannot convert ‘std::recursive_mutex* (*)[2]’ to ‘std::recursive_mutex (*)
[2][(((sizetype)(((ssizetype)((**here be long type information, since I'm using
templates a lot**, long unsigned int, std::less<long unsigned int>
>::size.std::atomic<long unsigned
int>::<anonymous>.std::__atomic_base<_IntTp>::operator
std::__atomic_base<_IntTp>::__int_type<long unsigned int>()) + -1)) + 1)]’ in
initialization
How can I obtain a pointer to 'locks'?
The error message is actually giving away the solution for free:
std::recursive_mutex * (*locks_2)[2] = &locks;
One can use the fact that this sort of thing has been officially declared to be ridiculously hard to get right for no apparent reason that the compiler cannot solve for you. If your compiler supports C++ 2011 that is. Use:
auto my_ptr = &locks; // point to locks, let the compiler worry about types
Requires that you compile your code as C++ 2011 though. (-std=c++11 for GCC).
locks is just an array of pointers. So you could use a pointer pointer to point to it.
std::recursive_mutex **locks_2 = locks;

Using private vars to initialize array

I'm trying to do a little application that would calculate some paths for a given graph.
I've created a class to handle simple graphs, as follows:
class SimpleGraph {
int _nbNodes;
int _nbLines;
protected:
int AdjMatrix[_nbNodes, _nbNodes]; //Error happens here...
int IncMatrix[_nbNodes, _nbLines]; //...and here!
public:
SimpleGraph(int nbNodes, int nbLines) { this->_nbNodes = nbNodes - 1; this->_nbLines = nbLines - 1; };
virtual bool isSimple();
};
At compilation time, I get an error on the two protected members declaration.
I don't understand what is wrong, as there is only one constructor that takes these values as parameters. As such, they cannot be uninitialized.
What am I missing here?
The compiler needs to know how much space to allocate for a member of class SimpleGraph. However, since AdjMatrix and IncMatrix are defined on the stack and their sizes are determined at run-time (i.e., after compilation), it cannot do that. Specifically, the standard says that the size of an array in a class must be a constexpr.
To fix this, you can:
Allocate AdjMatrix and IncMatrix on the heap instead and then you can allocate memory at runtime.
Use a fixed size for the two arrays and keep them on the stack.
--
Another major issue with your code is that you cannot create multi-dimensional arrays using a comma (AdjMatrix[int, int]). You must instead either use:
AdjMatrix[int][int]
AdjMatrix[int * int]
Objects in C++ have a fixed size that needs to be known at compilation time. The size of AdjMatrix and InMatrix are not known at compilation time, only at run time.
In the lines
int AdjMatrix[_nbNodes, _nbNodes]; //Error happens here...
int IncMatrix[_nbNodes, _nbLines]; //...and here!
The array notation is wrong. You cannot specify a 2 dimensional array that way in C++. The correct notation uses brackets on each dimension, as for instance:
int data[5][2];
Regarding the problem you are facing, the dimensions of an array in C++ must be specified at compile time, ie. the compiler must know what are the values used to indicate the array dimension when compiling the program. This is clearly not the case here. You must revert to use integer literals, as in my example, or change the code to use vectors:
std::vector<std::vector<int> > AdjMatrix;
and in the constructor:
SimpleGraph(int nbNodes, int nbLines) : AdjMatrix(nbNodes) {
for (int i = 0; i< nbNodes; i++)
AdjMatrix[i].resize(20);
}
Note that you won't need _nbNodes anymore, and use instead the size() method on AdjMatrix. You will have to do the same for IncMatrix.
Another option, if you know the values at compile time, is to use macros to define them symbolically.
#define NBNODES 20
int AdjMatrix[NBNODES][NBNODES];
but since you wish to pass them as constructor parameter, this may not fit your need. Still, if you know that the parameters are constants at compile time, you might be able use the C++11 constexpr qualifier on the constructor parameters.

C++ pass array argument to a function

I want to pass a reference to an array from one object GameModel to another PersonModel, store reference and then work with this array inside PersonModel just like inside GameModel, but...
I have a terrible misunderstanding of passing an array process: In the class PersonModel I want to pass an array by reference in a constructor (see code block below). But the marked line throws the compile error
PersonModel::PersonModel( int path[FieldSize::HEIGHT][FieldSize::WIDTH], int permissionLevel ) {
this->path = path; //<------ ERROR here:
//PersonModel.cpp:14:22: error: incompatible types in assignment of 'int (*)[30]' to 'int [31][30]'
this->permissionLevel = permissionLevel;
}
Here is the header file PersonModel.h
#ifndef PERSON_MODEL
#define PERSON_MODEL
#include "data/FieldSize.h"
namespace game{
class IntPosition;
class MotionDirection;
class PersonModel {
protected:
int path[FieldSize::HEIGHT][FieldSize::WIDTH];
int permissionLevel;
public:
PersonModel( int path[FieldSize::HEIGHT][FieldSize::WIDTH], int permissionLevel );
void setMotionDirection ( MotionDirection* md);
void step(long time);
void reset(long time);
};
}
#endif
As I see now, I can change the int path[FieldSize::HEIGHT][FieldSize::WIDTH]; declaration to int (*path)[FieldSize::WIDTH]; but it is much more confusing.
Help me understand this topic: what is the proper way to store the passed reference to an array to work with it later, like with usual 2D array.
UPDATE:
This array is a map of game field tiles properties represented by bit-masks, so it is read-only actually. All the incapsulated objects of GameModel class should read this array, but I definitely don't want to duplicate it or add some extra functionality.
There are no frameworks just bare Android-NDK.
I think you've fallen into the classic trap of believing someone who's told you that "arrays and pointers are the same in C".
The first thing I'd do would be to define a type for the array:
typedef int PathArray[FieldSize::HEIGHT][FieldSize::WIDTH];
You then don't need to worry about confusions between reference to array of ints vs array of references to ints.
Your PersonModel then contains a reference to one of these.
PathArray &path;
and, because its a reference it must be initialised in the constructors initialization list rather than in the constructor body.
PersonModel::PersonModel( PathArray &aPath, int aPermissionLevel ) :
path(aPath),
permissionLevel(aPermissionLevel)
{
}
Of course, holding references like this is a little scary so you might want to consider using a boost::shared_ptr or something similar instead to make the lifetime management more robust.
You cannot assign arrays as you do with value types in C++
int path[x][y] resolves to the type int (*)[y]
Possible solutions are:
Using memcpy/copy
Using std::array
You can't assign to an array like that. However you can use the fact that an array is a contiguous memory area, even when having an array of arrays, and use e.g. memcpy to copy the array:
memcpy(this->path, path, FieldSize::HEIGHT * FieldSize::WIDTH * sizeof(int));
You would have to pass a pointer to the 2d-array as you cannot pass the array as you have stated in the code snippet.
I would suggest using the STL array type. Admittedly std::array is C++ '11 standard and therefore old compiler may not support it. You can also use vector which has been around longer.
vector<vector<int>>path;
You will have to resize the 2d-vector in the constructor.
Indexing would look a bit funny:
path[1].[1] ....
With vectors, you can then pass it by reference.
the name of the array is a pointer on first element
so,
you can try
PersonModel( int (*path)[FieldSize::HEIGHT][FieldSize::WIDTH], int permissionLevel );
In C++ '=' implemented for primitive types like int and double but not for array(array is not a primitive type), so you should never use '=' to assign an array to new array, instead you should use something as memcpy to copy array. memcpy copy a memory over another memory, so you can use it to copy an array over another array:
// memcpy( dst, src, size );
memcpy( this->path, path, FieldSize::HEIGHT * FieldSize * WEIGHT * sizeof(int) );