• Create Account

## Possible C++ scope issue with class and vector of pointers

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

11 replies to this topic

### #1TimA  Members

139
Like
0Likes
Like

Posted 12 January 2013 - 10:31 AM

Alright it's been a while since I've programmed in C++ so this could be a simple fix but I'm just not seeing it.

I'm using Allegro 5, I have a main.cpp, a character.h, and a character.cpp

I have some test code in my main.cpp that works as it should:

ALLEGRO_BITMAP *characterSpriteSheet = al_load_bitmap("CharacterSpriteSheet.png");
characterAnimation walkingDown(6, 32, 32, 0, characterSpriteSheet);
std::vector <ALLEGRO_BITMAP*> testvector(1);
testvector[0] = al_create_sub_bitmap(characterSpriteSheet, 0, 0, 32, 32);

and then in the main game loop:

al_draw_bitmap(al_create_sub_bitmap(testvector[0], 0, 0, 32, 32), 0, 0, 0);

al_flip_display();  //Blit to screen

al_create_sub_bitmap creates an ALLEGRO_BITMAP* object that shares the same memory but with different size / clipping.

my character.h looks like this:

#ifndef CHARACTER_H
#define CHARACTER_H

#include "allegro5/allegro.h"

#include <vector>
#include <string>

class characterAnimation
{
public:
characterAnimation(short int numOfSteps, short int height, short int width, short int row, ALLEGRO_BITMAP *spriteSheet);
ALLEGRO_BITMAP *getNextFrame(void);
private:
short int numberOfSteps;
short int currentStep;
short int imageHeight;
short int imageWidth;
short int row;
std::vector <ALLEGRO_BITMAP*> images;
};

#endif


my character.cpp looks like this:

#include "character.h"

characterAnimation::characterAnimation(short int numOfSteps, short int height, short int width, short int animationRow, ALLEGRO_BITMAP *spriteSheet)
{
numberOfSteps = (numOfSteps - 1);
currentStep = 0;
imageHeight = height;
imageWidth = width;
row = animationRow;
std::vector <ALLEGRO_BITMAP*> images(numberOfSteps);

for(int x = 0; x <= numberOfSteps; x++)
{
images[x] = al_create_sub_bitmap(spriteSheet, (imageWidth * x), (imageHeight * row), imageWidth, imageHeight);
}

}

the characterAnimation::getNextFrame(void) function is currently setup just to return the first element (0) of the vector to make things easier right now (since it's not working)

The problem seems to be in characterAnimations constructor - I'm thinking that the al_create_sub_bitmap() created pointers goes out of scope and gets destroyed possibly at the end of the constructor? resulting in a bunch of pointers that don't go anywhere sensible.  Which would explain why my program crashes when I try to call al_draw_bitmap(images[x]).  My question is, is that what's happening?

Currently my program crashes only when I try to draw an element from characterAnimation::images to the screen, For some reason these pointers aren't getting set, or are being destroyed, I have no idea why though, so any help would be awesome.

### #2SiCrane  Moderators

11527
Like
3Likes
Like

Posted 12 January 2013 - 10:39 AM

You create a new local vector in your constructor and add the images to that, not to the member variable. Get rid of the local vector variable.

### #3TimA  Members

139
Like
0Likes
Like

Posted 12 January 2013 - 11:10 AM

I need the vector in the class populated with the sub-bitmaps - the constructor is meant to load a series of images into that vector to be stored.  Then characterAnimation::getNextFrame(void) will return the ALLEGRO_BITMAP* from the images vector when called from main....

ie.

main.cpp

#include "allegro5/allegro.h"

#include "character.h"

bool isRunning = true;

int main(void)
{
//allegro intialization stuff omitted

while(isRunning)
{
eventHandler();
al_draw_bitmap(walkingDown.getNextFrame(), 0, 0, 32, 32);  //draws the current animation sequence
al_flip_display();  //blits to screen
}
}

and the only difference in character.cpp is that the getNextFrame(void) function will look like this:

ALLEGRO_BITMAP *characterAnimation::getNextFrame(void)
{
int tempStep = currentStep;

if(currentStep == numberOfSteps)
{
currentStep = 0;
}
else
{
currentStep++;
}

return images[tempStep];

}

If i got rid of the member vector the class would be useless...unless I'm misunderstanding something.

### #4SiCrane  Moderators

11527
Like
2Likes
Like

Posted 12 January 2013 - 11:13 AM

Don't get rid of the member variable; get rid of the new vector local variable you have in the vector constructor.

### #5TimA  Members

139
Like
1Likes
Like

Posted 12 January 2013 - 11:44 AM

haha oooooh I see what I was doing now - thank you so much - is there anyway to initialize a vector in a class to a specific size in the constructor?  That's what I was trying to do, not create a local version of it.  Figured if I knew the starting size it'd be more efficient to create the vector to that size rather than using vector.push_back() to append a new element.  Do vectors allocate contiguous memory if initialized to size? I assume vectors can't do that when using push_back()? or maybe they re-create themselves after every added element so that it can fit into contiguous memory?

### #6FLeBlanc  Members

3133
Like
2Likes
Like

Posted 12 January 2013 - 11:48 AM

You can use initializer lists:
characterAnimation::characterAnimation(short int numOfSteps, short int height, short int width, short int animationRow, ALLEGRO_BITMAP *spriteSheet) :
numberOfSteps(numOfSteps-1), currentStep(0), imageHeight(height), imageWidth(width), row(animationRow), images(numberOfSteps)
{
for(int x = 0; x <= numberOfSteps; x++)
{
images[x] = al_create_sub_bitmap(spriteSheet, (imageWidth * x), (imageHeight * row), imageWidth, imageHeight);
}
}


### #7SiCrane  Moderators

11527
Like
2Likes
Like

Posted 12 January 2013 - 11:50 AM

You can use a member initialization list to initialize class members.
characterAnimation::characterAnimation(short int numOfSteps /* etc */) : images(numOfSteps)
{
//rest of constructor body
}

Vector growth happens exponentially. If the capacity isn't sufficient to support a push_back, it grows by some factor of the current size, often growing by 50% or 100%.

### #8mrbastard  Members

1576
Like
1Likes
Like

Posted 12 January 2013 - 01:15 PM

Do vectors allocate contiguous memory if initialized to size? I assume vectors can't do that when using push_back()? or maybe they re-create themselves after every added element so that it can fit into contiguous memory?

That's an astute question. In addition to setting the number of elements on construction as suggested above, you can also use vector::reserve to ensure a reasonable amount of space is available, without actually changing the number of elements 'in' the vector. This allows you to control when the allocation occurs, while still allowing you to use push_back or insertion iterators. While that's no better in this case, it's worth knowing.

### #9Llamaiyama  Members

133
Like
0Likes
Like

Posted 12 January 2013 - 02:05 PM

Do vectors allocate contiguous memory if initialized to size? I assume vectors can't do that when using push_back()? or maybe they re-create themselves after every added element so that it can fit into contiguous memory?

A vector is not required to be contiguous pre C++11, although the standard implicitly ensures that it's contiguous in order meet performance requirements.

In C++11 it is explicitly required to be contiguous:

(From draft standard, but it's essentially the same in the finalized version, emphasis added)

23.3.6.1 Class template vector overview [vector.overview]

1
A vector is a sequence container that supports random access iterators. In addition, it supports (amortized)
constant time insert and erase operations at the end; insert and erase in the middle take linear time. Storage
management is handled automatically, though hints can be given to improve efficiency. The elements of a
vector are stored contiguously, meaning that if v is a vector<T, Allocator> where T is some type other
than bool, then it obeys the identity &v[n] == &v[0] + n for all 0 <= n < v.size().

In reality, I know of no implementation that doesn't store elements in a contiguous manner. Also, there isn't a guarantee that a vector will grow exponentially, but all implementations I know of do this to meet the requirement of amortized constant insertionThe amount of growth, however, is dependent on the particular implementation.

### #10SiCrane  Moderators

11527
Like
1Likes
Like

Posted 12 January 2013 - 02:26 PM

A vector is not required to be contiguous pre C++11, although the standard implicitly ensures that it's contiguous in order meet performance requirements.
Actually, the contiguous requirement was added in C++03.

### #11Llamaiyama  Members

133
Like
0Likes
Like

Posted 12 January 2013 - 07:29 PM

A vector is not required to be contiguous pre C++11, although the standard implicitly ensures that it's contiguous in order meet performance requirements.
Actually, the contiguous requirement was added in C++03.

Oops you're right. I guess I mixed up 11 and 03 in my head

### #12TimA  Members

139
Like
0Likes
Like

Posted 12 January 2013 - 08:26 PM

You guys are awesome, thanks for all the info and quick response times.  The problem is now completely fixed and I learned a bit more about vectors.  I'll definitely be coming back next time I hit another snag I can't figure out.

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.