I have small question about std::vector. In main.h i try to make fixed size int vector
std::vector<int> foo(7);
But g++ gived this error:
../test/main.h:21:26: error: expected identifier before numeric constant
std::vector<int> foo(7);
../main/main.h:21:26: error: expected ',' or '...' before numeric constant
How can i create private vector variable of fixed size length? Or should i simply make in constructor
for(int i=0; i<7;i++){
foo.push_back(0);
}
Assuming foo is a data member, your syntax is invalid. In general, you can initialize a data member of type T like this:
T foo{ctor_args};
or this
T foo = T(ctor_args);
However, std::vector<int> has a constructor that takes an std::initializer_list<int>, which means that the first form would yield a size-1 vector with a single element of value 7. So you are stuck with the second form:
std::vector<int> foo = std::vector<int>(7);
If you are stuck with a pre-C++11 compiler, you would need to use a constructor:
class bar
{
public:
bar() : foo(7) {}
private:
std::vector<int> foo;
};
and take care to initialize the vector in all constructors (if applicable.)
The most efficient way to initialize a class member (other than built-in type), is to use the initialisation list.
So the best solution here, is to construct your vector of length 7 in the initilization list of your class constructor:
(I also recommend you to use a define for your fixed value 7. If you change it to 8 in the futur your will not have to change the value 7 on all your code)
file.h:
#define YOURCLASSFOOSIZE 7
class yourClass
{
public:
yourClass(): foo(YOURCLASSFOOSIZE) {}
private:
std::vector<int> foo;
};
file.cpp :
for(int i=0; i < YOURCLASSFOOSIZE; i++)
{
foo.push_back(0);
}
Related
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];
}
};
class Foo{
static vector<Point> vec[3];
};
So I have an array of three vectors. I need each vector to be initialized at compile time.
For example something that looks like this:
vec[0] = { {1,2}, {3,4}}; // contain two points
vec[1] = { {0, 0}}; // contain one point
vec[2] = {}; // empty
Is it possible to do this?
you need to declare it in the cpp file with the intialization list
in the cpp file:
vector<Poiint> Foo::vec={Point(1,2,3), Point(4,5,6), Point(8,9,10)};
where Point(x,y,z) is the constructor so it will populate the vector with three elements
in the class you should declare it like that:
static vector<Point> vec;
A work-around would be adding an internal static Class _init (name it the way you like), whose constructor performs the actual initializing.
Class Foo{
public:
static int bar;
static class _init{
public _init(){// do something to bar}
} Initializer;
};
// --- in .cpp
// define 'bar' and 'Initializer'
So that Initializer's constructor will be called to initialize bar.
It looks like the intention is more like:
static vector < vector<Point> > vec;
If so, then with some short testing in the C++11, Windows 64-bit C++Builder compiling and running, that obtains the desired result. As an additional experiment, after defining parameter-less and passed value constructors for the Point (class?) type used in the example, calling push_back on the multidimensional vec works as well:
vec.push_back( {{1,2}, {3,4}} );
vec.push_back( {{0,0}} );
vec.push_back( {{4,5}} );
I am confident the reason the Point class can be neglected is because the multidimensional vec vector has been declared to store Point instances. The last line in the OP above of passing an empty Point does not achieve anything, as can be shown when traversing the vec. The third element (index two), will not print a thing. The {4, 5} Point has been added to test traversing to all indices of the vec. Notice that there are two sets of curly braces inside the call of push_back. Without the outer set of curly braces, the compiler error says, "no matching member function for call to push_back."
Sample code to traverse the multidimensional vector (e.g. matrix or array):
//
// Declared a typedef to separate the vector row and the whole matrix
// Makes it simpler to traverse each vector row later. intVals is a
// test class with public integer elements "a" and "b". The intVals
// class substitutes for the Point type in the OP above.
//
typedef vector<intVals> vec_t;
vector<vec_t> matrix;
int jj;
for (int i = 0; i < 3; i++)
{
jj = 0;
for (vec_t::iterator j = matrix[i].begin(); j != matrix[i].end(); j++)
{
cout << "Matrix at index: " << i << ", element: " << jj << " a = " << (*j).a;
cout << " b = " << (*j).b << endl;
jj++;
}
}
Note that the outer loop is clamped at three. The real implementation could use the matrix::iterator instead (or a range for).
For additional reference on a multidimensional vector see the multidimensional vector, how to forum posting.
vec[0] = { {1,2}, {3,4}};
This won't work as there is no vector constructor that takes variable number of objects (works in C++11 with support of initializer_list).
To get around that, you can do this using a couple of arrays:
Point v1[2] = {Point(1,2), Point(3,4)};
Point v2[1] = {Point(0.0)};
vector<Point> Foo::vec[] = {vector<Point>(v1, v1+2), vector<Point>(v2, v2+1), vector<Point>()};
This uses the vector constructor that takes the begin and end iterators to construct the vector.
In C++11, I think you can do it this way:
vector<Point> Foo::vec[] = {{Point(1,2), Point(3,4)}, {Point(0,0)}, {}};
I was coding up a Union find data structure , and was trying to initialize the parent vector with a value parent[i]=i, Is there a way in c++ to initialize the vector like this , that is declaring a vector of size N , and not assigning fixed values to each element, rather position dependent value to each element. (without using any obvious for loops)
This is what I was looking for:
std::vector<int> parent(Initializer);
where Initializer is some class or a function.
To try out my hand a bit, I wrote this:
#include <iostream>
#include <vector>
using namespace std;
class Initializer {
private:
static int i;
public:
int operator() ()
{
return i++;
}
};
int main()
{
vector<int> parent(Initializer);
cout << parent[0];
return 0;
}
However I think I have messed up my concepts pretty bad here, and I am not getting what the declaration means, or what it is doing.
Please answer both the questions,
(1) How to initialize a vector with variable initial values.
(2) What exactly is the code I wrote doing?
This is a function declaration:
vector<int> parent(Initializer);
Becasue Initializer is a type name, you declared a function parent that takes Initializer as a (unnamed) parameter and returns vector<int>. See Most vexing parse.
To do what you want, you can do this:
std::vector<int> parent(N); // where N is the size you want
std::iota(parent.begin(), parent.end(), 0); // fill it with consecutive values
// starting with 0
There's std::generate algorithm that you can use to save result of a function (or function object) in a range:
std::generate(parent.begin(), parent.end(), Initializer());
Live demo.
There are several alternatives. If you want to initialize the vector with increasing values, then you can use std::iota.
std::vector<int> vec(size);
std::iota(std::begin(vec), std::end(vec), 0);
If you want something more general you could use std::generate.
std::vector<int> vec(size);
int n = 0;
std::generate(std::begin(vec), std::end(vec), [&n]() {return n++;});
I've got a class, and part of the input into the class is a vector (called Data) of variable length (lets say it has length N). I've included this after the function:
N = data_->size();
In the private section of the class, I want to declare an array double A[N][N];. However, when I try to do this, I get something saying
error: "N is not a type name, static, or enumerator".
How do I create the array A[N][N]?
Sorry if this is already explained somewhere else, as I'm very new to c++, so wouldn't even know what to look for!
Edit -- attached code:
class foo {
public:
foo (std::vector &data)
: data(data_)
{
N = data_->size();
M = /* four times the last member of data (which is a vector of positive integers)*/
}
private:
double A[M][M];
void foo(void)
{
for (std::size_t i=1; i<=M; ++i)
{
A[i][i] = 1;
}
}
};
Hope that makes some sort of sense... How would I be able to define A[M][M]? Maybe it's not possible to do it for M as M is a function of the data. If not possible for M, is it possible for N?
One possibility I can think of is that I can make A a std::vector< std::vector<double> > A and then push a lot of 0's or something into it, and THEN modify the values...
if you´re using the std::vector class you must creates the vector in a function of the data_ class (like the constructor, for example), using this sentence:
A = vector<vector<double> >(N, vector<double>(N, 0));
The first parameter of the parentheses is the size of the vector and the second is the type of data on it.
Sorry for my english, i´m spanish and my english isn´t very good.
You cannot do that. Arrays are types, and they have to be known at compile time. This includes their sizes. So you cannot have a dynamic array as part of your class. The closest thing you get is a pointer to manually allocated array, but that is in fact essentially a std::vector. So perhaps the easiest solution is to just have a vector of vectors, or perhaps a single vector of size N * N that you access in strides j + N * i.
Example:
std::vector< std::vector<int> > v(N, std::vector<int>(N));
Or:
std::vector< std::vector<int> > v;
//...
v.resize(N, std::vector<int>(N));
Access: v[2][4] = 8;
Update: Since you edited your answer, you can write something like this to get you an N * 4n vector, where data.back() == n:
std::vector<unsigned int> data = get_data(); // given!
std::vector< std::vector<double> > v(data.size(), std::vector<double>(4 * data.back()));
Hmmm...several issues here...
Neither N nor M are declared (either in the constructor or as members of foo)
You are trying to initialize a member data that is not declared (and you may mean data_(data) as the syntax is member(expression), not expression(member))
The argument to your constructor is an incomplete type: it needs to be std::vector< sometype >; if you want it to be generic you'll need to use templates or get some help from boost
You are not initializing the only member variable that you have declared (A)
void foo(void) is a problem because it is not the correct syntax for a constructor (which has no type) but uses the class name
Let's build up to something closer to what you want
Start with a class foo:
class foo {
};
with a constructor taking a single argument of type std::vector<double>
class foo {
public:
foo(std::vector<double> &data);
};
you want to initialize a member variable with the data
class foo {
private:
std::vector<double> data_;
public:
foo(std::vector<double> &data)
:data_(data)
{};
};
At this point I'll note that I would generally not put the definition of a non-trivial constructor in the class declaration, but in a implementation file instead, and consequently I would be able to put the declaration of member variable beneath the public section with the declaration of the constructor. But for compactness I'll leave this way here.
You want to capture and store the size of the data
class foo {
private:
std::vector<double> data_;
size_t N;
public:
foo(std::vector<double> &data)
:data_(data)
,N(data.size())
{};
};
At this point we still haven't made that multi-dimensional storage that you want, but now you have some decisions to make about how to manage the storage. If you use Kerrek SB's approach this looks something like
class foo {
private:
std::vector<double> data_;
size_t N;
std::vector< std::vector<double> > A;
public:
foo(std::vector<double> &data)
:data_(data)
,N(data.size())
,A()
{
A.resize(N);
for (size_t i=0; i<N; ++i) {
A[i].resize(N);
}
};
};
You need to create it dynamically, using a smart pointer if you do not want to manage memory yourself.
double **A;
in the constructor:
A = new double *[N];
for(i=0;i<N;++i)
{
A[i] = new double [N];
}
Not that you have to call delete in your destructor and now to obey the rule of three you have to have a copy constructor and a assignment operator... Using a smart pointer is better here: see the Boost smart pointer help page.
I am trying to compile this code:
class OthelloState {
public: // constructor
Othello(int r, int c);
/* other stuff */
private: // private data
const int rows;
const int columns;
int board[rows][columns];
}
I keep ending up with:
OthelloState.h:109: error: invalid use of non-static data member 'OthelloState::rows'
OthelloState.h:115: error: from this location
OthelloState.h:115: error: array bound is not an integer constant
OthelloState.h:112: error: invalid use of non-static data member 'OthelloState::columns'
OthelloState.h:115: error: from this location
OthelloState.h:115: error: array bound is not an integer constant
I assume that this means I have to make rows and columns static. But if I make them static, I cannot initialize either with from a constructor, the way I have to for this project...
Is there some other way I can do this?
PS: I know that in real Othello, the board is a square 8 by 8 grid...But after considering how long it would take the computer to generate the next best move on a partial 8 by 8 grid, we are not going to play with "real" Othello board (i.e. no predefined board sizes).
In C++, variable length arrays are not allowed. board[][] needs to know both of its dimensions at compile time. You can use vector<vector<int> > board;, if you want to initialize row and col at runtime.
class OthelloState {
public:
OthelloState(int r, int c);
private: // private data
const int rows; // should be 'unsigned int'
const int columns;
vector<vector<int> > board;
};
Other solution:
Suppose you know rows and cols at compile time then you can use template. That is as good as initializing row and col in constructor.
template<unsigned int row, unsigned int col>
class OthelloState {
public:
...
private:
int board[row][col];
};
Usage:
OthelloState<8,8> obj;
OthelloState<10,10> obj;
if it's always 8x8, then constants are a minimal solution. here's one way to declare it:
class OthelloState {
// ...
private:
enum { rows = 8, columns = 8 };
int board[rows][columns];
};
But after considering how long it would take the computer to generate
the next best move on a partial 8 by 8 grid, we are not going to play
with "real" Othello board (i.e. no predefined board sizes).
I deduce from that sentence that you're working on a homework assignment. If that's the case, then it might not be possible/practical for you to use Boost.MultiArray (unless your instructor advised you that it's okay to use Boost).
That leaves vector< vector<int> > which are a PITA to initialize properly. Before you can even use vector< vector<int> >, you have to loop through each inner vector and resize it.
Boost.MultiArray is basically just an overglorified wrapper around a 1D array of data. I therefore propose a third alternative: Roll up your own 2D wrapper around a flat one-dimensional vector. You can overload operator() to mimic the [][] behavior of 2D arrays:
int operator()(size_t row, size_t col) {/*compute index into 1D array*/}
I posted an example of this kind of wrapper here.
You're trying to dynamically define the size of a compile-time, fixed size array at runtime. You will need to dynamically allocate the memory. You also need your constructor to have the same name as your class
class OthelloState {
public: // constructor
OthelloState(int r, int c)
{
board = new int[r];
for(int i = 0; i < r; i++)
{
board[i] = new int[c];
}
}
/* other stuff */
private: // private data
const int rows;
const int columns;
int **board;
};
Make sure you have matching deletes for all your news in a destructor if you use this method, though