Suppose I have
vector<vector<int> > a;
which is indexed as
a[i][j] = stuff;
where i is "outer" and j is "inner"...
Then creating a reference to the "outer" vector is easy:
vector<int>& b = a[x];
Is there a nice way to create a reference to the inner?
vector<int>& b = a[<don't know>][x];
Thanks.
Unfortunately, no, there's no direct way of creating a reference like that because the compiler is treating this like
a.operator[] (/* ... don't know ... */).operator[] (x);
This only makes sense if the first call to operator [] actually hands back a vector.
However, what you can do is fake this behavior by introducing a new class that specifically handles the behavior. The idea is to have this class store the second index and provide an operator[] function that, given the first index, looks up the real value in the vector. Here's one example:
class IndexReverser { // Or, your favorite name
public:
IndexReverser(vector< vector<int> >& v, size_t index);
int& operator[] (size_t firstIndex);
private:
vector< vector<int> >& realVector;
const size_t secondIndex;
};
IndexReverser::IndexReverser(vector< vector<int> >&v,
size_t index) : realVector(v), secondIndex(index) {
// Handled in initialization list
}
int& IndexReverser::operator[] (size_t firstIndex) {
return realVector[firstIndex][secondIndex];
}
You could then write, for example, this:
IndexReverser ir(a, j);
ir[i] = 137;
You might need to provide a twin class to handle const vectors, and probably would want to parameterize the entire structure on the type of the elements being stored. I'm not sure if this is what you're looking for, but it least shows that in principle you can get the behavior you want.
This line:
vector<int>& b = a[x];
is not a reference to the outer vector but rather one of the inner vectors. Also note that there are possible many inner vectors.
Here's how to get a reference to the outer vector (although in general it would be pointless):
vector<vector<int> > &outer = a;
Getting a reference to one of the inner vectors looks something like this:
vector<int> &inner = a[x];
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];
}
};
I have defined one matrix class, and overloaded the + operator to be able to add instances of this class together.
class Matrix{
public:
vector<vector<int>> a;
Matrix & operator+(const Matrix& b)
{
vector<vector<int>>::const_iterator it0=b.a.begin();
vector<vector<int>>::iterator it1=this->a.begin();
vector<int>::iterator it2=it1->begin();
vector<int>::iterator it3=it1->end();
vector<int>::const_iterator it01=it0->begin();
for(it1;it1!=this->a.end();it1++)
{
it2=it1->begin();
it3=it1->end();
it01=it0->begin();
it0++;
// a.begin(),a.end(),b.begin(),ret.begin()
std::transform(it2,it3,it01,it2,std::plus<int>());
}
return *this;
}
};
But then, there is also another way of doing this,
class Matrix{
public:
vector<vector<int> > a;
Matrix & operator + (const Matrix &y) {
for (int m=0; m<y.a.size(); ++m) {
for (int n=0; n<y.a[0].size(); ++n) {
this->a[m][n] = this->a[m][n] + y.a[m][n];
}
}
return *this;
}};
The second form is shorter, but uses arrays directly, while the first one uses iterators. Maybe it's possible to do this with iterators in a shorter way, I'm not sure. I've tested with simple cases and they seem to be equally efficient.
What's the proper way of doing this?
For non-trivial classes (such as classes including a std::vector), in-place operations are often cheaper than allocating a new object and then (presumably) destroying one or both of the arguments. However, aggressive use of rvalue reference overloads can somewhat mitigate this.
Note that regardless of which function implementation I used, I would not use nested std::vectors - I would either use a single std::vector or better a std::unique_ptr<T[]> and then calculate the index as y*w+x (remember to bounds-check first).
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.
In C++ I have 2 STL vectors A and V. A has data and is able to change it, V only points to data but reads only and can't modify it. So if these two vectors are inside a class what will be the syntax of
Variables definition
assigning A reference into V
get_A() and get_V() will it return a reference or a pointer?
Also If I have other normal vectors like A, B, C, and D am I able to "insert" their references into V so that V can see them all one by one? For clearance V.size() will be equal to A.size() + B.size() + C.size().
Sorry for confusion,I think I've asked the question in wrong way
The vectors will be declared as
vector<Data> A;
vector<const Data *> V;
(Note that V cannot be a vector of const Data & because references are not Assignable, and vector requires an Assignable template type.)
Assigning a reference from A into V would look like this:
V[i] = &A[i];
I'm not sure what you mean by get_A and get_V. My best guess is that you are referring to what the results of operator[] on A and V are. A[i] returns a reference to a Data, that is a Data&. V[i] technically returns a reference to a const Data pointer, i.e. const Data * &, but effectively you would use it as a pointer, i.e. a const Data *.
Regarding the question about A, B, and C: if they are the all vectors of same type, and they do not change size, you could set up V to contain pointers to the elements in each one of them. But if they do change size, then appending an element to, say, A, after having set V up would mean you would have to insert the pointer to the new element of A into the correct offset of V, which is possible but seems like a hassle.
A quick example of setting up such a V would look like this:
vector<Data const *> V;
for (size_t i = 0; i < A.size(); ++i) { V.push_back(&A[i]); }
for (size_t i = 0; i < B.size(); ++i) { V.push_back(&B[i]); }
for (size_t i = 0; i < C.size(); ++i) { V.push_back(&C[i]); }
I believe what you are describing is something like a const alias for the data vector. What I am saying is that you need to work with a const reference to vector A.
An example (completely out of the blue, but describes my suggestion and understanding of the situation quite well):
class someClass
{
public:
const std::vector & V() const
{
return A;
}
private:
std::vector<int> A;
};
From what I get from constness, this "protects" A through showing only the const version when someone "accesses" the vector through someClass::V().
I have a function which creates an array of Maps:
map<string, int> *pMap
And a function which writes maps to the array:
int iAddMap(map<string, int> mapToAdd, map<string, int> *m, int i)
{
m = &(pMap[i]);
memcpy(m, mapToAdd, sizeof(map<string, int>));
}
And a function to get maps from the array
map<string, int>& getMap(int i)
{
return pMap[i];
}
I can write maps to the array without any issue, but every get call results in a seg fault:
int val;
// val defined after this
map<string, int> * pGetMap = &(getMap(val));
Any suggestions on why this is happening?
You cannot use memcpy() to copy objects like maps, or indeed any other kind of C++ container - you need to use assignment, which takes into account the map's underlying structure and se,mantics. And you should be using a vector <map>, as you actually seem to want a copy rather than a pointer.
Never ever use memcpy for copying an object of a map (or whatever class, for that matter) - use assignment or copy constructor instead. memcpy is a C function, which has no idea of the internal structure of a C++ object, so it is almost guaranteed to mess things up.
Also you would better use an std::vector<map<string, int> > instead of an array:
std::vector<map<string, int> > maps;
void addMap(const map<string, int>& mapToAdd, int i)
{
maps[i] = mapToAdd;
}
map<string, int>& getMap(int i)
{
return maps[i];
}
Note: addMap does not return anything in your example code, so I changed its return type to void. Also I pass mapToAdd as const reference rather than by value.
This seems like an unholy mix of C and C++ programming, begin with changing:
memcpy(m, mapToAdd, sizeof(map<string, int>));
to
*m = *mapToAdd;
Also in the function
int iAddMap(map<string, int> mapToAdd, map<string, int> *m, int i)
What is the purpose of m? Any modifications to m won't be seen outside of this function.