开发者

How to check if memory has aready been released in Destructor?

I have a simple tank wars style game using the allegro open source library. In my tank class, I initialize arrays of pointers to bitmap objects to 0. Then I create new objects with an allegro function create_bitmap which allocates the memory and initializes it.

Then I go about my business as usual.

The problem is, when I go to release the bitmap memory in the class destructor like a good OO boy, I crash the program because in this specific program, the allegro library does its cleanup (which releases the bitmap objects it created) before the class goes out of scope and is destroyed. It doesn't set my pointers to NULL again though so I can't check if the bitmaps are still valid and if I try to release them they will crash the program.

Is there any way around this? Can I check for valid pointers if they are not NULL? How can I be SURE that the memory is freed if the class is used a differe开发者_StackOverflow中文版nt way within the program. As it stands right now, I'm essentially calling new without delete and I don't like it.


I think the problem is not that allegro releases the bitmaps itself (or otherwise you wouldn't need to release them at exit) but that allegro library has been deinitialized before the destructor is called.

int main()
{
    ObjectManagingBitmaps o;
    ...
    return 0;
    //allegro automatically shut down here
} //o destructor invoked here
END_OF_MAIN()

What you can do to ensure that the destructor is invoked first is to use an artificial scope:

int main()
{
    {
    ObjectManagingBitmaps o;
    ...
    } //o destructor invoked here
    return 0;
    //allegro automatically shut down here
} 
END_OF_MAIN()


You shouldn't be using arrays of raw pointers. Allegro comes with a create_bitmap and a destroy_bitmap function. That maps very nicely to the C++ concept of constructors and desctrutors. You should have an AllegroPlusPlus::bitmap class, which manages exactly one bitmap. Your Tank class can tehn simply have an array of those.

This is a seperation of responsibilities. The tank class should not know too much about bitmaps and their memoy management, and the bitmap class should handle precisely one bitmap.

You want to recycle bitmaps in your Tank class. This is no problem; it can be done easily with a good implementation of bitmap::operator=(bitmap const&) or other overloads. But again, make that assignment a responsibility of the bitmap class, not the tank class.


Can I check for valid pointers if they are not NULL?

No. But in your case you don’t need to. Since Allegro promises to take care of its resources you don’t have to (and must not) meddle in the resource handling of Allegro resources. In particular, since you don’t even know how the resources are allocated, you cannot deallocate them.


The key to manage memory explicitly is that while you can have several pointers to the same memory area, at any one time, only one of them is the designated owner, while all other only share it. When heap objects own other heap objects, they constitute a tree, rooted in a globally or locally scoped variable somewhere.

You should consider Allegro to be the owner of memory areas you pass into it, and your own pointer just to be a shared pointer, once you return from the initial Allegro call.

And no, barring some allocator trickery, you have no standard way of determining whether memory is valid or not. Allocator trickery can be useful for debugging purposes, but don't mess with the internals of a library.


Sounds like a rather horrible leaky abstraction

You cannot hope to find a safe method of destroying memory if you do not know exactly how it has been allocated. The cleanup function sounds like it's there for a reason and doing a job - just gotta live with it.

You could of course wrap these bits and include some documentation in comments so that other developers don't fall into the same trap.

Also profile your application to make sure there's no leaking.


When is the destructor being called? Is it after the Allegro library has been shut down? If so then can you delete all the objects first?


Are you sure you are using this correctly? I have dug out some of my old Allegro code and I have a constructor with a create_bitmap call and a destructor with a release_bitmap call and it worked fine.

I don't remember anything about Allegro releasing memory for you automatically. Are you accidently overwriting the pointer with some non-memory value? Is there another place where this pointer is being freed?


Use reference counting when dealing with multiple pointers to heap memory. Basically, if you have multiple references to the same memory and delete one, the other reference might still think it exists.

http://en.wikipedia.org/wiki/Reference_counting


I'd say you should ensure that your objects are all destructed before shutting Allegro down, you can do this easily enough by (if they're on-stack) closing the scope they exist in before shutting down Allegro.

If you need to shut down Allegro earlier than this (e.g. because of a fatal error) then you could just call exit in which case no destructors get run (but your program still won't crash).

Don't spend too much time making sure that the program cleans up on exit, save your effort on making sure it doesn't leak while it's running :)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜