I have a function that takes in the number of rows and columns and initialises a vector of vector with default values of the object 'cell' and return the pointer to that vector.
//Cell class
class cell{
public:
int cost, parent;
cell(int cost = 0, int parent = 0) : cost(cost), parent(parent){}
}
//The initialisation function
vector<vector<cell> >* init_table(int n_rows, int n_cols){
//Error line
vector<vector<cell> >* table = new vector<vector<cell>(n_cols)> (n_rows);
//Some(very few) special cells need a different value so I do that here
return table; //Return the pointer
}
It seems the compiler resolves (n_cols)> (n_rows) like a > operation and not create n_cols copies of cell objects and n_rows copies of vector objects. How can I initialise the vector without manually looping through and pushing default valued cells in the vector?
Since C++ compilers usually have return value optimization, you can just do simply
vector<vector<cell> > init_table(int n_rows, int n_cols)
{
return vector<vector<cell> >(n_rows, vector<cell>(n_cols));
}
and writing
vector<vector<cell> > my_table = init_table(int n_rows, int n_cols);
will be as efficient as "new"-ing a vector, but this is safer.
Oh I now get it. I should initialise the outer vector with the inner vector through it's constructor like
vector<vector<cell> >* table = new vector<vector<cell> > (n_rows, vector<cell>(n_cols));
and not as a template parameter. It is working now.
Related
New to C++ here. I have a pointer variable type vector, which I initialized to be n by m, where n and m are int's given as input. Here is how I initialize it.
std::vector<std::vector<int>>* memo; // This is as a member.
void test(int m, int n) {
memo = new std::vector<std::vector<int>>(m, *new std::vector<int>(n, 0)); // This is inside a method.
}
Later, I try to assign a certain element.
int ans = 5; // In my actual code, it's something else, but I'm just simplifying it.
memo[i][j] = ans; // This gives an error.
I thought I just needed to deference it, because right now it is a pointer type. So I changed it to this:
*memo[i][j] = ans;
However now I got a new error:
C++ no operator matches these operands operand types are: * std::vector<int, std::allocator<int>>
Why isn't this working, and how can I make it work?
For starters this declaration
std::vector<std::vector<int>>* memo;
does not make great sense. It would be better to declare the data member like
std::vector<std::vector<int>> memo;
This allocation
memo = new std::vector<std::vector<int>>(m, *new std::vector<int>(n, 0));
Is incorrect. The elements of the vector are not pointers. You should write
memo = new std::vector<std::vector<int>>(m, std::vector<int>(n, 0));
or
memo = new std::vector<std::vector<int>>(m, std::vector<int>(n ));
It seems it is the reason of other your problems.
To set a value to such a vector you should write for example
( *memo )[i][j] = ans;
If to declare the data member as not a pointer like for example
std::vector<std::vector<int>> memo;
then in a function you could assign it like
memo.assign( m, std::vector<int>( n ) );
I have a dynamically allocated 2D array Volatility[r][c] with r rows and c columns in C++. Is it somehow possible to create a pointer ptrColumn to a certain column c1, such that I can access the element (r1,c1) with ptrColumn[r1]?
So far, I tried to create dynamic pointers. But I didn't manage to do it.
Thank you!
You need a stride iterator. The ++ operator for a normal pointer returns a new pointer with an offset 1; for a stride iterator, the ++ operator will return a new stride iterator with a physical offset c; And so for operator [], + and --; Here is a simple example:
template< typename Iterator_Type >
struct stride_iterator
{
typedef typename std::iterator_traits<Iterator_Type>::value_type value_type;
typedef typename std::iterator_traits<Iterator_Type>::reference reference;
typedef typename std::iterator_traits<Iterator_Type>::difference_type difference_type;
typedef typename std::iterator_traits<Iterator_Type>::pointer pointer;
typedef typename std::iterator_traits<Iterator_Type>::iterator_category iterator_category;
Iterator_Type iterator_;
difference_type step_;
stride_iterator( Iterator_Type it, difference_type dt ) : iterator_(it), step_(dt) {}
reference operator []( difference_type dt )
{ return iterator_[dt*step_]; }
//other ctors, dtor and operators
};
This case, suppose the pointer holding the 2D array is double** dat, and the dimension for the array is r by c, you can create a column iterator at column index c1 with
auto col_itor = stride_iterator<double*>{ dat + c1, c };
and access the element at dat[r1][c1] with operator []
auto& elem = col_itor[r1];
No, that's not possible. One alternative you have is to create another 2D array with a traspose of the original array but is just useless because you'd have to update this array every time original array changes. Perhaps there is other ways to do it but an array of columns just don't.
Usually the first dimention is for row index, and the second for column.
First you should allocate memory for array of pointers (e.g. int *) and save addres as pointer to pointers:
int** Volatility = new int * [r];
Then arrange loop to allocate memory for each row. E.g.:
for(int i = 0; i < r; i++)
Volatility[i] = new int [c];
But it is your desition how to work with indexes.
If you want to work with columns on first index, just change the logic:
int r = 5, c = 10;
int** Volatility = new int * [c];
// allocate memory for each column
for(int i = 0; i < c; i++)
{
Volatility[i] = new int [r];
}
As you see Volatility[col][row] is a single element, and Volatility[col] is a pointer to columt. But now you cannot work with pointer to row.
The easiest way, for me, is to reserve the block of memory:
double* array2d= new double[r*c];
then, you can calculate the pointers as array2d+index*r (remember, the block of memory stores the array column by column, from the first to the last column).
IF you want to calculate the pointers to rows, use array2d+index*r (in this case, the memory stores the array row after row.
If you want the pointers in some place to use double operator [][], you could use:
double **array= new double*[r];
for (int i=1; i<r; ++i)
array[i]= array[i-1]+c;
For this code, you could use array[i][j] in your code.
In my platformer game which I'm writing in Visual C++, each level will initially be stored as a 2-dimensional array of ints. I decided it would make more sense to store this array in a class, so I created a class called Level. It looks like this:
class Level {
private:
int map[20][30];
public:
Level(int a[20][30]) {
map = a;
}
int getcell(int row, int column) {
return map[row][column];
}
};
As far as I can see - from looking up tutorials on class constructors, and passing 2-dimensional arrays as parameters, this should work, so I really don't understand why it doesn't.
On the line where I do map = a, I get an error: Error: expression must be a modifiable lvalue. I've looked this error up on stackoverflow, but I can't find any answers which relate to my problem.
So, how can I fix this error?
This doesn't really have anything to do with a constructor. You cannot assign arrays in C++. Whether in the constructor, or anywhere else.
There are two ways to work around it. The first way is the brute force way. Instead of
map = a;
write a loop to copy the contents of the array from the constructor's parameter into the class member array.
The second way is to stuff the array into an intermediate class:
class Level {
public:
struct level_map {
int map[20][30];
};
private:
level_map map;
public:
Level(const level_map &initial_map) : map(initial_map)
{
}
int getcell(int row, int column) {
return level_map.map[row][column];
}
};
This may or may not be practical, and introduces a little bit more complexity.
But the real answer here is to use std::vectors instead of plain arrays, which will solve all of these problems.
Others have already mentioned the real reason: you cannot assign an array to another using = operator. My two cents about your class:
map is not a good name, it may get conflict with std::map if using namespace std; or using std::map was specified somewhere.
The constant array sizes make this class non-reusable. Class should be flexible to allow any N*M sized 2D array. For this, better to use vector<vector<int>>.
getcell should be a const method, and it should do error checking with row and column numbers passed.
If you want this class to have static-sized array sizes and compile time, you may use class templates with row and column sizes as non type template arguments.
template<size_t row, size_t column>
class Level
{
int _map[row][column];
public:
Level(int src[row][column])
{
memcpy(_map, src, sizeof(_map)); // why not simply 'memcpy' ?
}
};
int main()
{
int source[10][2] = { {1, 2}, {3,4} };
Level<10, 2> ten_by_2(source);
}
Here the map is a constant value, which could not been assigned as an lvalue. This could be fixed by iterating the element of the array, and assign a[i][j] to map[i][j].
class Level {
private:
int map[20][30];
public:
Level(int a[20][30]) {
for(int i = 0; i < 20; ++i)
for(int j = 0; j < 30; ++j)
map[i][j] = a[i][j];
}
int getcell(int row, int column) {
return map[row][column];
}
};
I got a little problem with templates and pointer. I'm trying to create a 2d array for some different matrices with different types. I have to do it with templates and references where it makes sense.
My main function looks like this, I'm not allowed to change it:
int main(){
int row, column;
cin >> row;
cin >> column;
int** M1;
double** M2;
reserve(M1, row, column);
reserve(M2, row, column);
return 0;
}
So my reserve function would look something like this:
template <typename S>
void reserve(S &x, int row, int column){
x = new S*[row];
for(int i = 0; i < row; ++i) {
x[i] = new S[column];
}
}
My problem is that I'm not getting the solution for this function. I tried it every way I could think about but nothing works.
I think the problem is that I'm not working correct with the type** pointer in combination with the type-parameter. In the version I posted above, im getting errors like:
error: cannot convert ‘int****’ to ‘int**’ in assignment x = new S*[row];
Would love if someone could help me fixing this function.
Changing the signature of reserve to this should fix the compile error
template <typename S>
void reserve(S **&x, int row, int column)
Alternatively, you can implement reserve so that it returns the newly allocated array
template <typename S>
S** reserve(int row, int column)
{
S** x = new S*[row];
for (int i = 0; i < row; ++i) {
x[i] = new S[column];
}
return x;
}
Remember to delete the array using delete [] when you are done using it:)
Maybe something like this might help you; try to encapsulate the whole concept into a class object like this:
template<typename T>
class Matrix {
public:
typedef std::vector<T> Row;
private:
std::vector<Row> Mat;
unsigned numberRows;
unsigned numberColumns;
public:
Matrix();
explicit Matrix( std::vector<Row>& vRows );
Matrix( unsigned numRows, unsigned numColumns );
Matrix( unsigned numRows, unsigned numColumns, T** data );
~Matrix();
private:
void reserve( unsigned int numRows, unsigned int numColumns );
};
Where this reserve() method is part of the class object where only this class has access to it. This would act as a helper function for your class in implementing its multiple constructors. If you want to use dynamic memory for the elements this can be expanded to this:
template<typename T>
class Matrix {
public:
typedef std::vector<std::shared_ptr<T>> Row;
private:
std::vector<Row> Mat;
// All Else Would Be The Same; Only The Internal Methods Would Slightly
// Vary Due To The Use Of Smart Pointer And Dynamic Memory.
};
Then in your main this will simplify code.
int main() {
// Using Default Constructor
Matrix<float> fMat1;
// Using std::vector<Row> To Construct A Matrix
Matrix<int>::Row row1;
Matrix<int>::Row row2;
Matrix<int>::Row row3;
std::vector<Matrix<int>::Row> vRows
Matrix<int> iMat2( vRows );
// A Construct That Knows The Size Of The Matrix;
// But Doesn't Have The Data
Matrix<double> dMat3( 4, 4 ); // This Will Create A Size Of 4x4 Of
// Doubles And Initialize Everything To 0
// Same As Above, But Passing In Raw Data By Double Pointer.
float** pData = nullptr;
// Populate Pointer's Elements
unsigned int row, col;
// Store Size Of Row & Col Based On Pointer's Elements
Matrix<float>( row, col, pData );
return 0;
}
And that is about it! The constructors shouldn't be that hard to implement. And if you are only working with stack objects the first definition of the class will work, but if you need dynamic memory of all objects the second one will suite your needs and the use of smart pointers makes the cleaning up of dynamic memory much cleaner, easier and safer. Less prone to memory leaks.
This would also allow you to create a matrix when you have the data available upon creation of the matrix; or to make an empty matrix container available to set aside memory for later on when you are ready to populate it. You would just have to add the necessary methods to set, get data elements, and any appropriate operator overloads for performing basic operations. Maybe some public methods to do common work on data or to test if data is in matrix, etc.
Because this Matrix class is template the way it is; it is not subject to just basic raw day types. This can store class objects, structure, function pointers, events, threads, files and even more!
We're trying to use a 2D vector because we want a 2D array that will grow dynamically.
We tried this:
In the class declaration:
vector<vector<double> > table;
But then table doesn't seem to be allocated. We get a segfault when we try to access members.
So then we tried this:
Class Declaration:
vector<vector<double> >* table;
Constructor:
table = new vector<vector<double> >;
But now we the way we accessed it before (with [][]) doesn't work.
We tried a dummy class with this:
class myClass {
public:
myClass();
~myClass();
vector<vector<double> > t;
};
myClass::myClass()
{
t = vector<vector<double> > (10, vector<double>(10));
}
But it wouldn't free properly and we got core dumps. Also when we tried to grow the array, we'd have expclitly construct each new row.
Ex:
t[50] = vector<double>(5);
t[50][10] = 10;
If we didn't do it like this, we'd get a segfault
You'll need to resize the tables before you access elements.
vector<vector<double> > table;
table.resize(10);
for (int i = 0; i < 10; ++i)
table[i].resize(20);
Make sure your vectors are large enough to store your elements. If a vector t has size N, the last element you can access is t[N-1].
t = vector<vector<double> > (10, vector<double>(10));
t[50] = vector<double>(5); // This is wrong! Vector size is 10, you access 50th.
t[50][10] = 10; // Wrong again! Vector size 5, you access 10th.
If you have Boost installed try using Boost Multi-array.
You can access the element in [][] manner by derefrencing.
Vector<vector<double>> *table ;
table = new vector<vector<double>> ( n, vector<double>( m, 0.0)) ;
cout << (*table)[i][j] ;
Most of the times, this works perfectly well.