At the moment I have one question about vectors but I want to leave this open ended so if I obtain more questions I can come back here.

So I was looking at different containers for a player inventory that can be dynamically changed on the fly due to events within the game I am working on (like buying new inventory slots) and I wanted to give vectors a try since using an array for this was going to be a pita/impossible.

However I am a little foggy on exactly how vectors operate, sepcifcally in their initilizaiton as a class member. With arrays you need to initlize each element in that array in the constructor after declaring it in the header however when attempting to do the same with this vector I created I get the red lines of failure in VS2010.

Are the elements in a vector supposed to be set in the constructor or are the elements just added as needed without actually needing to "set" them like you do with arrays?

Hello, Vectors are arrays, but, arrays are defined in size (memory allocations) whereas Vectors are dynamically assigned, in memory. So for example, if you reach the maximum capacity in an array it will run out of memory whereas vectors will just change it's size dynamically and therefore allocate more memory.

How you assign them, I don't really get what you mean but here's an example:

#include <iostream>
#include <vector>

using namespace std;
int main(int argc, char *argv[]) {

    vector<int> numbers; // Declare vector without a size.

    vector<string> names(2); // Define a vector with a size of 2 elements

    names.push_back("Phorce");
    names.push_back("Bob");
    names.push_back("Jimmy");
    /*
        Note how I have 3 elements, in an array, it would force a memory error
        if not handled.
    */

    for(unsigned i=0; (i < names.size()); i++)
    {
        cout << names[i] << endl;

    }

}

In terms of classes, ok:

#include <iostream>
#include <vector>

using namespace std;

class Foo
{

    public:
        // add elements to the vector
        void addNames(string theName)
        {
            this->names.push_back(theName);
        }

        // retrive the vector
        vector<string> getNames()
        {
            return this->names;

        }
    private:

    vector<string> names;
};

int main(int argc, char *argv[]) {

    Foo foo;

    foo.addNames("Phorce");
    foo.addNames("Jimmy");

    vector<string> theNames = foo.getNames();

    for(unsigned i=0; (i < theNames.size()); i++)
    {
        cout << theNames[i] << endl;

    }

}

Basic example, probably going to get bad rep but that's how I see vectors (In a simple way). Hope this helps you a bit :)!

P.S. Can you post examples of how you're trying to implement the vectors? It might help a bit..

Edited 4 Years Ago by phorce

With std::vector, you can do either!
If you know what the vector should contain when your class is instantiated, you can initialise the vector with whatever it needs to contain in your class constructor. Or if you know how many elements it will need to contain, you could initialise it to allocate a fixed amount of space (to avoid reallocations). But vectors are dynamic containers, they are not like ordinary C style arrays. So if you just want your class object to start out with an empty vector, then you can declare it as a member of your class and it will be given a default, empty initialisation and you can populate it on the fly.

Regarding your initialisation problems, if you post a snippet of your code; I'm sure somebody here can steer you in the right direction!

Originally I was trying to initilize the vector like I would an array that was a class member by using an element list in the contructor:

pSInv[pSSSlots] = {0,0,0,0,0,0,0,0,0,0};

and I tried this as well:

pSInv(pSSSlots);

But niether worked. However I see now I had the wrong syntax and I should have been adding them via function using pushback instead of trying to use the above methods:

addISpace(pSSSlots);

That is in the contructor which then calls this function:

void Player::addISpace (int i)
{
    for (;i > 0; i--)
    {
        pSInv.push-back(0);
    }
}

Is my understanding of how push-back works correct in the above code? What if I want to add an element to the end of the vector so that the ordering of the elements in front of it remains the same? Is there a "push-forward" method for vectors that can be used?

An additional question, are vector elements retreived the same way array elements are? Using a cout example:

for (int i = 0; i < sizeof(stringArray)-1;i++)
{
    cout << stringArray[i] << endl;
}

Or are they retreived with a different method?

Edited 4 Years Ago by Geowil: added a question

Yes, vector elements can be printed the same way as arrays, just like in your example.. (Why haven't you compiled some code to test?!?).

void Player::addISpace (int i)
{
    for (;i > 0; i--)
    {
        pSInv.push-back(0);
    }
}

I don't get this code.. Let's say that pSInv was a vector of type int, then you would push_back i rather than 0.

Hope this helps :)

I don't get this code.. Let's say that pSInv was a vector of type int, then you would push_back i rather than 0.

Phorce, the way that my inventory will work is that the vector will store the id number for that specific item. When the inventory is called up a function will pass any non-default item id's to a function in my dataSystem class so it can pull the relevent information out of the itemDB matrix I have globally defined there. It will then send that info back to the calling class so it can generate the information seen on-screen.

The code you referenced sets the starting number of inventory slots given by pSSSLots (player station storage slots) to the default value of zero so the inventory window/menu does not have a conniption.

From Phorce's original example:

vector<string> names(2); // Define a vector with a size of 2 elements

names.push_back("Phorce");
names.push_back("Bob");
names.push_back("Jimmy");

/*
    Note how I have 3 elements, in an array, it would force a memory error
    if not handled.
*/

This doesn't do what is stated. When you do vector< string > names(2) you make a vector with 2 default-constructed elements. Calling push_back then adds new elements onto the end of the vector, so what you end up with in this example is a vector with FIVE elements, the first two of which have only their default values. In this case, that's going to mean blank strings, since that's the default construction behaviour of string

@OP:
You said that

and I tried this as well:
pSInv(pSSSlots);

Is pSInv a vector and pSSSlots a size_t-like values? If so, that should work. It sounds like you want to give the vector an intial size and fill it with some default values in the constructor and then maybe add other things to it later on. If that's the case, here's an example of how I would do that:

class ClassWithVectorMember
{
    /// A vector of unsiged values for your slots
    std::vector< unsigned > m_vSInv;

public :
    /// A value that provides the number of slots (it's static const, so
    /// can assign it a value in the class declaration)
    static const size_t s_iSSSlots = 10;

    /// A constructor that initialises m_vSInv to a size of s_iSSSlots
    /// and gives a value of zero to each element
    ClassWithVectorMember() : m_vSInv( s_iSSSlots, 0 ) {}

    // Other public methods here...
};

Note that the constructor of std::vector can take two arguments. The first is the size and the second is the value that you want each of the elements to take.

Also, I would avoid using this method to initialise vectors

for( int i = 0; i < n; ++i )
    v.push_back( x );

push_back is a great feature of std::vector, but it's not magic. Although std::vector takes care of its own memory management, it still has to allocate specific amounts of memory for the things that it stores. So, when you call push_back, it has to check if it has enough memory to store the new object before adding it. If it does, then it just adds the object, no problem. If it doesn't, then it has to go off and allocate a new block of memory somewhere and then call all the copy constructors of all the objects it currently holds, to get them in the new memory block. Then it can add the new object. After that it has to free the old memory, which will involve calling the destructors of all the objects in the old memory. As you can imagine, this can be expensive in terms of time (especially, if destruction or copy construction aren't cheap). In fact, all implementations of std::vector that I know have a strategy where they do something like allocate ever-increasing sizes of memory each time they run out, so the number of times everything has to be moved to new memory decreases roughly logarithmically with the number of times you call push_back.

So, if you want to add a large, defined number of things (call it n) to your vector, then you can manually resize the vector to the right size before and use its operator[] to give them values:

size_t iOldSize = myVector.size();
myVector.resize( iOldSize + n );

for ( size_t i = iOldSize; i < myVector.size(); ++i )
    myVector[ i ] = newValue;

There are times when this won't work or isn't a good idea though. For example, if the thing that the vector contains isn't default constructable or if default construction is expensive. When you call resize on a vector, it makes the vector the specified size (assigning more memory, if necessary) and calls the default constructor for each of the new elements. If the thing that the vector contains doesn't have a default constructor, then you will get a comilation error. Alternatively, if default construction is really expensive for some reason, then you don't want to waste time doing it just so that you can immediately over-write the values with the ones that you actually want. In this case push_back is absolutely the right thing to do. However, if we know that we're going to add n things, then we can warn the vector that we're going to need to make room for that many things (but not to actually do anything with the memory) by using the member function reserve:

myVector.reserve( myVector.size() + n );
for ( size_t i = 0; i < n; ++i )
    myVector.push_back( newValue );

You should also rememer that when you call reserve, you don't affect the actual number of things in the vector, so size still returns the old value:

// initialise to a size
std::vector< int > v(2);
std::cout << v.size() << std::endl;    // Prints '2'

// resize
v.resize( 4 );
std::cout << v.size() << std::endl;     // Prints '4'

// reseve
v.reserve( 6 );
std::cout << v.size() << std::endl;     // Prints '4'

// push_back
v.push_back( 1 );
std::cout << v.size() << std::endl;     // Prints '5'

Is my understanding of how push-back works correct in the above code? What if I want to add an element to the end of the vector so that the ordering of the elements in front of it remains the same? Is there a "push-forward" method for vectors that can be used?

I'm not sure the your understanding is completely correct, the way you have defined your loop indicates that you might think that push_back might be used to add values to a vector from back to front. This is not the case. push_back simply adds a new member onto the end of the vector (that is in the position with the highest index). If your vector has 3 elements (with indices 0, 1 & 2) then calling push_back will add a fourth element with index 3. There isn't a push_forward method (but I think you're asking about this due to your above mis-understanding of what push_back does). In fact QList, which is a vector-like class in the Qt library, has a push_front method which allows you to add a new item to the other end of the list, i.e. in the position with the lowest index.

Anyway, you can find out about what all the members of std::vector do here. I look at that site on a daily basis!

Edited 4 Years Ago by ravenous: typo

This article has been dead for over six months. Start a new discussion instead.