Ctor call #1: pRoom = new Room_Data; - This calls the constructor to create a new Room_Data
Ctor call #2: rMap[pRoom->vnum] - This calls the constructor to create a new "blank" Room_Data to put at key=2400. Remember that the [] operator will create an entry if there isn't already an entry there.
Dtor call #1, Ctor Call #3: = *pRoom; - This reassigns the previous "blank" Room_Data. Therefore calling its destructor, and then calling the copy constructor on Room_Data to copy *pRoom into the map. Note you don't notice the copy ctor because you're not logging the copy ctor in your Room_Data class
Dtor call #2: /*rMap going out of scope*/ - This causes all elements to be destructed. Therefore the copy of the Room_Data that is in the map gets destructed
Note that there were 3 ctor calls and only 2 dtor calls. You just missed the copy ctor call because you're not watching the copy ctor... you're only watching the default ctor.
This is because 'pRoom' was never deleted. This is a memory leak.
EDIT:
Actually... I'm wrong. I don't think map would destruct then copy construct the object. I think it would just assign it.
#include <iostream>
#include <limits>
#include <map>
#include <cstring>
usingnamespace std;
class Room_Data
{
public:
Room_Data() {cout<<"Default Constructor of " << this <<endl;}
Room_Data(const Room_Data & rd)
{
cout << "Copy Constructor of "<< this << " from " << &rd << endl;
name=rd.name;
vnum=rd.vnum;
}
Room_Data & operator=(const Room_Data & rd)
{
cout << this << '=' << &rd << endl;
name=rd.name;
vnum=rd.vnum;
}
~Room_Data() {cout<<"Destructor of" << this <<endl;}
char* name;
int vnum;
};
int main()
{
cout << "code block 1:\n" << endl;
Room_Data *pRoom;
pRoom = new Room_Data;
pRoom->vnum = 2400;
map<int, Room_Data> rMap;
map<int, Room_Data>::reverse_iterator iter;
cout << "\ncode block 2:\n" << endl;
rMap[pRoom->vnum] = *pRoom;
for ( iter = rMap.rbegin() ; iter != rMap.rend(); iter++ )
{
cout<<iter->second.vnum<<endl;
}
cout << "\ncode block 3:\n" << endl;
cout<<pRoom->vnum<<endl;
delete pRoom;
cout << "Press ENTER to quit." << std::flush;
std::cin.ignore( std::numeric_limits <std::streamsize> ::max(), '\n' );
return 0;
}
As you see, this line here -> rMap[pRoom->vnum] = *pRoom; calls the default constructor once, the copy constructor twice, the destructor twice and the assignment operator once.
Disch wrote:
Remember that the [] operator will create an entry if there isn't already an entry there.
Yes, and to be more specific, a call to operator[] is equivalent to:
The default constructor is obviously called to create the new entry in the map. The two copy constructor (and destructor) calls take place in the make_pair function:
Okay, apparently std::map is doing lots of copies behind the scenes. I honestly don't know what they're all about.
Reprise:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
// Construct
pRoom = new Room_Data;
// Construct
// Copy
// Copy
// Destruct
// Destruct
rMap[pRoom->vnum] // the [] operator does all that
// just does an assignment, no ctors/dtors called
= *pRoom;
// Destruct
/* rMap going out of scope */
Note that rMap doesn't go out of scope until after you pause so you don't see that 'Destruct' line on the screen. You might be able to see it flash by after you hit Enter though.
As for why creating a new element with the [] calls the copy ctor twice... I have no idea. std::map just must be doing some weird things behind the scenes. It might not do that on every implementation though.
EDIT: ah! of course! I forgot that everything is in std::pairs. Yeah that might explain it. Good call @ roshi.
It should be (*((rMap.insert(make_pair(2400,Room_Data()))).first)).second = *pRoom;
I tried it too and it calls one more copy constructor and destructor than the typical operator[] call... Don't really know what's going on... :/
judas97 wrote:
With all those calls to ctor when adding only 1 pointer to map mean its not an efficient or prefered way of storing them?
I wouldn't say so. It depends on what you want to do. If you just want to store items, use a vector or a deque or a list (look them up in the reference section of the site). A map is an associative container that stores elements in pairs of keys-values and automatically sorts the elements by their keys. It's designed so that you can access the values fast, using their keys. If that's what you want, map (or multimap) is the way to go.