Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Buffer Class

This thread is locked; no one can reply to it. rss feed Print
Buffer Class
Charles256
Member #8,370
February 2007

In the destructor when I go to delete bitmaps it kicks out an error. Memory access violation. What am I doing wrong? Any ideas? By the way, at the bottom is an implementation of the code.

1class buffering
2{
3 private:
4 BITMAP * buffer;
5 vector<BITMAP *> bitmaps;
6 
7 public:
8 buffering()
9 {
10 buffer=create_bitmap(SCREEN_W,SCREEN_H);
11 }
12 void add_bitmap(BITMAP *picture,int x=0,int y=0)
13 {
14 draw_sprite(buffer,picture,x,y);
15 bool exists=false;
16 for(int i=0;i<bitmaps.size();i++)
17 {
18 if(picture==bitmaps<i>)
19 {
20 exists=true;
21 }
22 }
23 if(!exists)
24 {
25 bitmaps.push_back(picture);
26 }
27 }
28 void add_stretched_bitmap(BITMAP * picture,int x=0, int y=0,int width=SCREEN_W, int height=SCREEN_H)
29 {
30 stretch_sprite(buffer,picture,x,y,width,height);
31 bool exists=false;
32 for(int i=0;i<bitmaps.size();i++)
33 {
34 if(picture==bitmaps<i>)
35 {
36 exists=true;
37 }
38 }
39 if(!exists)
40 {
41 bitmaps.push_back(picture);
42 }
43 }
44 void render()
45 {
46 vsync();
47 draw_sprite(screen,buffer,0,0);
48 }
49 ~buffering()
50 {
51 for(int i=0;i<bitmaps.size();i++)
52 {
53 destroy_bitmap(bitmaps<i>);
54 }
55 }
56};

1int main(void)
2{
3 setup();
4 buffering game_screen;
5 BITMAP *title,*test;
6 title = load_bitmap("images/title.bmp", NULL);
7 test = load_bitmap("images/test.bmp", NULL);
8 while(!key[KEY_ESC])
9 {
10 game_screen.add_stretched_bitmap(title,0,0);
11 game_screen.add_bitmap(test,255,255);
12 game_screen.render();
13 rest(120);
14 }
15 allegro_exit();
16 return 0;
17}
18END_OF_MAIN()

set up just sets up allegro and the screen, nothing vitally important.

Onewing
Member #6,152
August 2005
avatar

You're constantly adding pointers to the same bitmap in the while loop. The vector contains all these duplicate pointers and when it tries to delete the first duplicate it comes to in the destructor...well, boom! ;)

------------
Solo-Games.org | My Tech Blog: The Digital Helm

Charles256
Member #8,370
February 2007

read my class carefully. i added a for loop to ensure no duplicate entries. :-D and i'm adding the pointers into a vector ( think advanced array) so i'm not really stacking them on top of each other. I wish it was that simple, I'd have it solved all ready. :-D Try compiling the code and making it run? :-D I added the code if it helps. :-D

Kauhiz
Member #4,798
July 2004

This is wrong:

if(picture==bitmaps<i>)
{
  exists=true;
}

You're comparing pointers. Basically, this will never be true, since obviously the pointers won't be identical.

As for your problem, I believe the destructor gets called after allegro_exit(). You probably realize why this is a big no-no.

---
It's Ridge Racer! RIIIIIDGE RAAAAACER!

Charles256
Member #8,370
February 2007

Actually, pointers will be identical. That's partially why they're called pointers... they point to a place and if an object points to the same thing another object does their memory locations are exactly the same. Promise. Run the code yourself, eat an apple, whatever. Either way, calling it after allegro_exit was the problem so the fixed code is as follows. feel free to take the buffering class if you like.

1#include <allegro.h>
2#include <string>
3#include <vector>
4 
5using namespace std;
6class buffering
7{
8 private:
9 BITMAP * buffer;
10 vector<BITMAP *> bitmaps;
11 
12 public:
13 buffering()
14 {
15 buffer=create_bitmap(SCREEN_W,SCREEN_H);
16 }
17 void add_bitmap(BITMAP *picture,int x=0,int y=0)
18 {
19 draw_sprite(buffer,picture,x,y);
20 bool exists=false;
21 for(int i=0;i<bitmaps.size();i++)
22 {
23 if(picture==bitmaps<i>)
24 {
25 exists=true;
26 }
27 }
28 if(!exists)
29 {
30 bitmaps.push_back(picture);
31 }
32 }
33 void add_stretched_bitmap(BITMAP * picture,int x=0, int y=0,int width=SCREEN_W, int height=SCREEN_H)
34 {
35 stretch_sprite(buffer,picture,x,y,width,height);
36 bool exists=false;
37 for(int i=0;i<bitmaps.size();i++)
38 {
39 if(picture==bitmaps<i>)
40 {
41 exists=true;
42 }
43 }
44 if(!exists)
45 {
46 bitmaps.push_back(picture);
47 }
48 }
49 void render()
50 {
51 vsync();
52 draw_sprite(screen,buffer,0,0);
53 }
54 destroy_bitmaps()
55 {
56 for(int i=0;i<bitmaps.size();i++)
57 {
58 destroy_bitmap(bitmaps<i>);
59 }
60 }
61};
62void setup()
63{
64 allegro_init();
65 set_color_depth(16);
66 install_keyboard();
67 install_mouse();
68 install_timer(); /*don't know if you need this*/
69 if (set_gfx_mode(GFX_AUTODETECT_WINDOWED,1024,768,0,0)!=0)
70 {
71 set_gfx_mode(GFX_TEXT,0,0,0,0);
72 allegro_message(allegro_error);
73 exit(1);
74 }
75 show_mouse(screen);
76}
77 
78int main(void)
79{
80 setup();
81 buffering game_screen;
82 BITMAP *title,*test;
83 title = load_bitmap("images/title.bmp", NULL);
84 test = load_bitmap("images/test.bmp", NULL);
85 while(!key[KEY_ESC])
86 {
87 game_screen.add_stretched_bitmap(title,0,0);
88 game_screen.add_bitmap(test,255,255);
89 game_screen.render();
90 rest(120);
91 }
92 game_screen.destroy_bitmaps();
93 allegro_exit();
94 return 0;
95}
96END_OF_MAIN()

anonymous
Member #8025
November 2006

You are right about the pointers pointing to the same place. However, calling the destructor manually is walking on thin ice. When main() ends, the destructor will be called again, so what you have here is undefined behaviour and it is just pure luck that it "fixes" the problem this time.

One way, if you want to control when the object gets destroyed, is to allocate it with new and call delete where you have the explicit destructor call. This ensures that the destructor gets called right there and just once.

See for yourself:

1#include <iostream>
2 
3class Test
4{
5 public:
6 Test() {std::cout << "Test()\n";}
7 ~Test() {std::cout << "~Test()\n";}
8};
9 
10int main()
11{
12 std::cout << "Explicit destructor call test:\n";
13 { //new scope
14 Test a;
15 a.~Test(); //bad!!!
16 } //second destructor call here!
17 std::cout << "Testing with dynamic allocation:\n";
18 {
19 Test* a = new Test;
20 delete a;
21 }
22 std::cout << "That's all folks!\n";
23 std::cin.get();
24}

Charles256
Member #8,370
February 2007

you're absolutely right. much better approach. rename destructor to an actual function called destry_bitmaps and run at end of program. tada. :-D

Kauhiz
Member #4,798
July 2004

No, you're actually right about the pointers. I thought you meant to compare the actual images. I mean, checking to see if it's a pointer to the same object doesn't really make that much sense, does it?

Wouldn't it be a lot simpler to just make sure you don't call the function for the same bitmap several times? Suppose the vector is already packed and you want to add a bitmap to it. First it would stretch the bitmap, then it'd go through the entire vector just to find out the bitmap's already there. Wouldn't it be a lot faster to just make sure in your code that the bitmap doesn't get added more than once?

---
It's Ridge Racer! RIIIIIDGE RAAAAACER!

Onewing
Member #6,152
August 2005
avatar

Quote:

you're absolutely right. much better approach. rename destructor to an actual function called destry_bitmaps and run at end of program. tada.

I don't think that's what he/she (being anonymous) meant. Instead of using "buffering game_screen", use "buffering *game_screen = new buffering; ...; delete game_screen;".

------------
Solo-Games.org | My Tech Blog: The Digital Helm

Charles256
Member #8,370
February 2007

hum...that'd work too...getting down to semantics though. :-D or maybe...hum......we'll see. As for the making sure it's not sent to screen more than once I thought it was the only way? I miss something?

Kauhiz
Member #4,798
July 2004

Well, tbh, I don't even know why you need the vector in the first place. You don't seem to be using it for anything apart from destroying the bitmaps. Seeing how that was the cause of the problem in the first place, if the only reason you have the vector is for destroying those bitmaps, I'd suggest you get rid of it and just destroy the bitmaps manually. Maybe it's just me, but I can see major headaches resulting from the way you do it right now. :P

Also, I just noticed that you don't seem to destroy buffer at any point.

---
It's Ridge Racer! RIIIIIDGE RAAAAACER!

Go to: