std::map
stores a copy of the object you insert. When the
object is removed, it is this copy which is destructed. So
after m[1] = t1;
, there are two identical instances of
CTestMap
: t1
and the one in the map.
Also: m[1] = t1;
will first create a new entry in the map,
using the default constructor, and later assign t1
to it.
In general, if you want to trace instance lifetime like this,
you need provide a user defined copy constructor and assignment
operator which trace as well. And you probably want to output
the this
pointer in all of the traces. (Another technique
would be to dote each object with an immutable unique
identifier:
#define TRACE(m) std::cout << #m << '(' << m_objectId << ')' << std::endl
static int currentObjectId = 0;
class TestMap
{
int m_id;
int const m_objectId;
public:
TestMap()
: m_id( 0 )
, m_objectId( ++ currentObjectId )
{
TRACE(DFLT);
}
TestMap( int id )
: m_id( id )
, m_objectId( ++ currentObjectId )
{
TRACE(CTOR);
}
TestMap( TestMap const& other )
: m_id( other.m_id )
, m_objectId( ++ currentObjectId )
{
TRACE(COPY);
}
~TestMap()
{
TRACE(DTOR);
}
TestMap& operator=( TestMap const& other )
{
m_id = other.m_id;
TRACE(ASGN);
return *this;
}
};
You might want to add additional information (like m_id
) to
the trace as well.
Also: your last output invokes undefined behavior. After
m.find(i)
, you should check first that the iterator hasn't
returned m.end()
. If it has, dereferencing isn't allowed. So
your test output should be something like:
void
testOutput( std::map<int, TestMap> const& m, int i )
{
std::map<int, TestMap>::const_iterator entry = m.find( i );
if ( entry == m.end() ) {
std::cout << "no object at " << i << std::endl;
} else {
std::out << "object " << entry->second.m_id << " at " << i << std::endl;
}
}
(Finally: I think Microsoft has preempted the C
prefix for
classes, so you should avoid it. If you want a prefix, choose
something else, to avoid confusion.)