Ok...I've not really ever messed with the STL map template, so I may be doing this wrong...
My problem is that the destructor for Tile is NOT being called! I have read the description for map, but it does not call the destructor(s) as it should for some reason!
1 | #include <map> |
2 | using std::map; |
3 | using std::pair; |
4 | enum TerrainTypes |
5 | { |
6 | Terrain_Plains, |
7 | Terrain_Forest, |
8 | }; |
9 | class Tile |
10 | { |
11 | public: |
12 | Tile() |
13 | { |
14 | type = Terrain_Plains; |
15 | printf("Tile created.\n"); |
16 | } |
17 | ~Tile() |
18 | { |
19 | printf("Tile destroyed.\n"); |
20 | } |
21 | enum TerrainType type; |
22 | BITMAP *image; |
23 | }; |
24 | class Map |
25 | { |
26 | public: |
27 | Map() |
28 | { |
29 | Tile *pTile = new Tile; |
30 | pTile->type = Terrain_Forest; |
31 | tiles.insert ( pair<int,Tile*>(0,pTile) ); |
32 | printf("size of tiles<int,Tile*>: %i\n",tiles.size()); |
33 | tiles.clear(); |
34 | printf("After CLEAR()...size of tiles<int,Tile*>: %i\n",tiles.size()); |
35 | } |
36 | ~Map() |
37 | { |
38 | tiles.clear(); |
39 | } |
40 | map<int,Tile*> tiles; |
41 | }; |
Probably something I've done that is stupid....hehehe
As always...Thanks in advance,
Donald
IIRC, clear just clears the map, not calling the destructor or anything. You will have to iterate through the map yourself, deleting each pointer stored.
Clear content
All the elements in the container are dropped: their destructors are called, and then they are removed from the container, leaving it with a size of 0.
Maybe I am just confused as to what/who's destructor clear is calling????
A pointer doesn't have a deconstructor though. If they were just tiles (not tile*s) then it would work as you are expecting.
So...the clear function does not dereference the pointers (as in this case?)
How would I add elements to the map without having to worry about them going out of scope?
... void SomeFunction( map<int,Tile> &tiles ) { Tile aTile; tiles.insert(pair<int,Tile>0,aTile); } ...
Would that be acceptable? I thought that since this would go out of scope, the map class would not contain valid data anymore...or is it that it is calling a copy constructor for the temporary?
[Edit 1]
Ok...I tryed this, it is ok...but calls the copy constructor...how do you avoid that? Using references/pointers....which is where I am at in the beginning...
[/Edit]
That's right. If you had been storing objects instead of pointers, the destructors would've been called; but the way you've done it now, you need to go through it.
EDIT: As for your reply there, yes, that's valid. There'll be a copy of the object in the map.
Thanks to all...
I get confused with pointers every once in a while for some stupid reason.... I don't know why I let them confuse me so...
Working insert without calling copy constructor:
Uh... that's not a good idea. That's an access violation waiting to happen.
That's going to give you invalid pointers as soon as pTile goes out of scope. The easiest solution, IMO, would be to do what you were doing before and just to iterate the map and delete each object.
I was hoping for some kind of "automatic" cleanup when the map object goes out of scope, but I guess I'll have to manually delete all the objects....damn!
Again, Thanks to X-G and BAF,
Donald
There is such a thing: store objects instead of pointers.
Ok then...two part question...
One...how would I do THAT (store objects instead of pointers)?
Two...would this be correct (from code before):
map<int,Tile*>::iterator it; for ( it=tiles.begin(); it != tiles.end(); it++ ) { delete (&it); }
1) map<int, Tile>
2) No. delete (*it);
I tried your delete (*it)...I got this error:
error: type ‘struct std::pair<const int, Tile*>’ argument given to ‘delete’, expected pointer
Second:
As for your adding object code...I get multiple calls to the copy constructor and then therefor multiple calls to the destructor. I don't really want that:
I got this error:
Oops, sorry. I keep forgetting that map iterators aren't like the other ones. I think it's i->second() or something like that. Check the manual.
I don't really want that:
There's no way around it. Write your constructors and destructors to cope with it.
(Also, maps overload the [] operator: tiles[0] = Tile(...);)
Well, for just one add operation...I get 5 calls to the destructor on exit! That seems like crap! I might just end up using a list instead.
Lists aren't all that much better. You're still going to have to write proper ctors/dtors... that goes for all STL types.
Yeah....noticed that with the list class as well... Damn it...I don't like all the extra calls to the copy constructor and the extra calls to the destructor....such is life I guess....Thanks for the help X-G!
Why were smart pointers not mentioned, this whole time?
You want a pointer that will call the destructor of the object that it points to as soon as it goes out of scope, yeah?
y halo thar, Smart Pointers. (part of Boost)
http://www.boost.org/libs/smart_ptr/smart_ptr.htm
Edit: Oh, okay, nevermind, cookies were already given. Then I retract my help, seeing as it's not wanted.
Kibiz0r: I'm guessing because smart_ptr isn't part of the standard library (auto_ptr is, but it doesn't like being placed into a container).
Well, you can write your own template easy enough.
I second the smart pointer solution. Spending so much time to avoid using a tool that works...
I figure it was a good opportunity for him to learn how these things work.
I figure it was a good opportunity for him to learn how these things work.
I for one agree with you.
Also, maps overload the [] operator:
tiles[0] = Tile(...);
Insert is a bit faster I think (depending on the speed of your default ctor).
tiles.insert ( pair<int,Tile>(0,pTile) );
Its a bit easier / cleaner to use make_pair
tiles.insert ( make_pair(0,pTile) );
auto_ptr ... doesn't like being placed into a container.
Hm? I was always under the impression that it would go into a container just fine.
Yeah, if you're spending time trying to make your stuff faster by switching [x] for table.insert, you really suck at optimizing.
Hm? I was always under the impression that it would go into a container just fine.
The copy constructor transfers ownership of the pointer'd object, which will break a lot of container functions.
The copy constructor transfers ownership of the pointer'd object, which will break a lot of container functions.
Which functions break?
Perhaps "a lot" was too brash.
Really, just some of the <algorithm> functions.
Only ones I'm sure of are the copy() functions, though I suspect fill() uses a copy constructor.
According to http://www.awprofessional.com/articles/article.asp?p=30642&seqNum=9&rl=1, a container of auto_ptrs ought to give you a compiler error. I wouldn't know, I pretty much only use boost::shared_ptr.
Only ones I'm sure of are the copy() functions, though I suspect fill() uses a copy constructor.
Pretty much every container type uses the copy constructor. What makes them "fail" is that the 'copied from' elements go to NULL. Which isn't really failing, it just means you have to know what you're doing.
In fact, the standard defines auto_ptr in such a way that it's illegal to instantiate an STL container with an auto_ptr element type; such usage should produce a compile-time error (and probably a cryptic one, at that). However, many current implementations lag behind the standard.
This is the interesting point here. Lets assume 'element type' means the type in vector<type>.
Okay, I did some research. Apparently his not the only guy claiming this. Heres an article on auto_ptr.
So the standards committee bent over backwards to do everything it could to help you out: The Standard auto_ptr was deliberately and specifically designed to break if you try to use it with the standard containers (or, at least, to break with most natural implementations of the standard library). To do this, the committee used a trick: auto_ptr's copy constructor and copy assignment operator take references to non-const to the right-hand-side object. The standard containers' single-element insert() functions take a reference to const, and hence won't work with auto_ptrs.
So looks like the standards committee doesn't like auto_ptr in container types. Thats a shame. I have to say I disagree with them.