std::vector question

Started by
17 comments, last by password 17 years, 6 months ago
If I create a two dimensional std::vector (4x4) like this: vector <vector<int> > LBlock(4, vector<int>(4)); Can I somehow initialize the elements in the vector like a normal array like this? I have to do this in order to get the order of the 0's and 1's the way I want it.

LBlock = {{0, 0, 0, 0},
          {0, 0, 0, 0},
          {0, 0, 0, 0},
          {0, 0, 0, 0}};

Question #2 Can I allot a two dimensional vector to a two dimensional array somehow. If this works, I don't have to worry about initializing the vectors the way I mentioned above. Neither vecBlock = arrBlock; or type casting works, is there any other way?
Advertisement
(1) Is there a reason you don't want to use the standard push_back function to initialise your vector?
  for( int firstIndex = 0; firstIndex < 4; firstIndex++ ){  for( int secondIndex = 0; secondIndex < 4; secondIndex++ )  {     (LBlock[firstIndex]).push_back( 0 );  }}


(2) Depending on the size of your arrays and vectors you could just loop through the elements.

Cheers
Amos
[EDIT - Sorry Amos - you beat me to it [smile]]

I may be wrong, but I am pretty sure that the answer is no to both of those questions.

vector data is allocated on the heap, even when the vector itself is static, so if nothing else, that would preclude being able to initialise it with the syntax above.

And I am not aware of any implicit conversion from a 2D array to a vector of vectors. For a start, they have different properties - a 2D array is always rectangular but a vector of vectors is not.

It is fairly trivial to write such a converter though, so you could initialise a 2D array statically then, on start up, use a function to copy this into a vector of vectors.

int Data[3][3]={{ 0,1,0 },                { 1,0,1 },                { 0,1,0 }};std::vector<std::vector<int> > Vec;void Init(){    Vec.resize(3);    for(int Y=0;Y<3;++Y)        {        for(int X=0;X<3;++X)            {            Vec[Y].push_back(Data[Y][X])); // or is that Data[X][Y]? I can never remember            }        }}


I think that is right. I get a bit confused by 2D arrays and avoid them like the plague to be honest.

If your container is always going to be rectangluar, I understand that there is a boost::multidimensional_array (or something) that may be useful. Alternatively, here's a class I use for 2D game maps:

class Map{private:    std::vector<int> V; int W,H;public:    Map(int Width,int Height) : W(Width),H(Height) { V.resize(W*H); }    int &operator()(int X,int Y);    int operator()(int X,int Y) const;    int Width() const { return W; }    int Height() const { return H; }    class BoundsError{ };};int &Map::operator()(int X,int Y){    if(X<0 || X>=W || Y<0 || Y>=H) throw BoundsError();    return V[(Y*W)+X];}int Map::operator()(int X,int Y) const{    if(X<0 || X>=W || Y<0 || Y>=H) throw BoundsError();    return V[(Y*W)+X];}int main(){    Map map(10,10);    map(3,2)=23;    std::cout << map(9,4) << std::endl; // etc}


This approach maintains the invariant that your container is rectangular and it also guarantees that the data is contiguous in memory, which a vector of vectors does not.

HTH Paul
Quote:Can I somehow initialize the elements in the vector like a normal array like this?


No, only normal arrays can be initialized thus, although there is discussion about extending C++ in this direction.

Quote:Can I allot a two dimensional vector to a two dimensional array somehow.


No. For starters you don't have a 2D vector, but a vector of vectors, each of which exists independently and not really as an integral part of a 2D structure. The fact that those vectors have been themselves put in a vector is completely incidental from their point of view.

There do exist true multidimensional array classes, like boost::multi_array. Also, depending on how exactly you plan on using the data, the std::valarray class may be what you are looking for.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
I didn't realize I could put the push_backs into a function like that. That's probably the easiest way I can make it. Something like this:

void SetPiece(int Data[]) {    Vec.resize(3); // not sure what this line does though, can only guess :)    for(int Y=0;Y<4;++Y) {        for(int X=0;X<4;++X) {            piece[Y].push_back(Data[Y][X]));        }    }}SetPiece(LBlock);


Probably have to change it to a vector with vector's though, since i've used that in the program so far. I hope they extend the language and makes this possible though, I find it really useful sometimes. Thank you all.
you could always use std::fill or std::fill_n:

http://support.roguewave.com/support/docs/sourcepro/edition9/html/stdlibref/fill.html

also, it might be "better" to just have a 1D vector and index it by ( x + MAX_Y * y ); nested vectors of the same type is just a lot of overhead for no real additional functionality.

-me
Plus if you're going to be initialising your vector of vectors because you already know its dimensions do you really need a vector or would a 2D array suit your needs better?

Cheers
Amos
Quote:Original post by password
Vec.resize(3); // not sure what this line does though, can only guess :)


Sets the size of the vector to 3. If there were originally fewer elements in the vector, the new elements are default-initialized. If there were more, the vector gets truncated.

Quote:Probably have to change it to a vector with vector's though, since i've used that in the program so far.


Incidentally, if you're only going to use the vector as a static array, you may be better off just using an array in the first place, or grab a STL array wrapper like boost::array or std::tr1::array (where available).


Quote:I hope they extend the language and makes this possible though, I find it really useful sometimes. Thank you all.


If you are curious, check out the current discussion. For more, go here and scroll down to or search for the papers about "Initializer lists".

[Edited by - Fruny on October 9, 2006 5:58:41 PM]
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Hey I dont got any live code but I can tell you somethin, im making a game that is using a PLETHORA of multidimentional[sic] vectors in it.
The way I make a normal vector behave like a multidimensional one is to create a width variable and use that to controll moving "up" and "down".
Heres the logic like so.

vector <int> board(9, 0);for (int i = 0;i < board.size(); i++)    display board;This gets displayed.000000000int boardWidth = 3;int j = 1;for (int i = 0;i < board.size(); i++){    display board;    j++;    if (j == boardWidth)       newline;}This gets displayed.000000000

if you wanted to move something up or down on the board, you simply add or subtract the width of the board.

if you want to use X and Y coordinates heres an little algorithm I made that will convert a vector location into X and Y coordinated, and another one that will take X and Y coordinated and convert them into a vector spot.

Here this takes a vector location and makes it into x and y coordinated.
int x = vector loacation + 1;int y = 0;while (x > boardWidth){        x -= boardWidth;	y++;}

This will take X and Y coordinates and return a vector location.
int XY(int x, int y, boardWidth){	x--;	y--;		while (y > 0)		{			y--;			x += boardWidth;		}	return x;}

so you could do...
board[XY(1,1,3)] = 1;orboard[5] = 1;

both are the same thing.

Hope I was of some assistance.
Not meaning to knock your code, Kaanin, but your functions to convert could be far more simply written and avoid loops all together:

int XYtoIndex(int X,int Y,int Width){    return (Y*Width)+X;}void IndextoXY(int Index,int Width,int &X,int &Y){    X=Index%Width;    Y=Index/Width;}

This topic is closed to new replies.

Advertisement