当我从std::map
删除元素时,如果调用了默认析构函数,那我就很好了。这是我做的一个例子:
class CTestMap{
public:
CTestMap() {
std::cout << "default constructor called" << std::endl;
}
CTestMap(int id) {
std::cout << "created object: " << id << std::endl;
m_id = id;
}
~CTestMap() {
std::cout << "destroyed object: " << this->m_id << std::endl;
}
int get_id(){
return m_id;
}
int m_id;
};
int main(void){
std::map<int, CTestMap>m;
std::map<int, CTestMap>::iterator m_it;
std::cout << "created map " << std::endl;
CTestMap t1(1);
std::cout << "created test object: " << t1.get_id() << std::endl;
CTestMap t2(2);
std::cout << "created test object: " << t2.get_id() << std::endl;
CTestMap t3(3);
std::cout << "created test object: " << t3.get_id() << std::endl;
m[1] = t1;
m_it = m.find(1);
std::cout << "inserted test object: " << m_it->second.get_id() << std::endl;
m[2] = t2;
m_it = m.find(2);
std::cout << "inserted test object: " << m_it->second.get_id() << std::endl;
m[3] = t3;
m_it = m.find(3);
std::cout << "inserted test object: " << m_it->second.get_id() << std::endl;
m_it = m.find(1);
std::cout << "will now erased test object: " << m_it->second.get_id() << std::endl;
m.erase(m.find(1));
std::cout << "erased test object: " << m[1].get_id() << std::endl;
m_it = m.find(1);
std::cout << "object shall no longer exist: " << m_it->second.get_id() << std::endl;
while(1);
return 0;
}
这是输出:
./htest
created map
created object: 1
created test object: 1
created object: 2
created test object: 2
created object: 3
created test object: 3
default constructor called
destroyed object: 9377935
destroyed object: 9377935
inserted test object: 1
default constructor called
destroyed object: 9377935
destroyed object: 9377935
inserted test object: 2
default constructor called
destroyed object: 9377935
destroyed object: 9377935
inserted test object: 3
will now erased test object: 1
destroyed object: 1
default constructor called
destroyed object: 158830600
destroyed object: 158830600
erased test object: 158830600
object shall no longer exist: 158830600
问题是:
std::map
,它的析构函数被称为?这是一般的行为吗?
std::map
?我找不到这个信息。delete
?答案 0 :(得分:6)
std::map
存储您插入的对象的副本。当。。。的时候
对象被删除,这是被破坏的副本。所以
在m[1] = t1;
之后,有两个相同的实例
CTestMap
:t1
和地图中的m[1] = t1;
。
另外:t1
将首先在地图中创建一个新条目,
使用默认构造函数,稍后将this
分配给它。
通常,如果要跟踪这样的实例生存期,
您需要提供用户定义的复制构造函数和赋值
跟踪的运算符。你可能想要输出
所有跟踪中的#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;
}
};
指针。 (另一种技术
将每个对象用不可变的唯一对象
标识符
m_id
您可能想要添加其他信息(例如m.find(i)
)
跟踪也是如此。
另外:您的上一个输出调用未定义的行为。后
m.end()
,你应该首先检查迭代器没有
返回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;
}
}
。如果有,则不允许解除引用。所以
你的测试输出应该是这样的:
C
(最后:我认为微软已经抢占了{{1}}前缀 类,所以你应该避免它。如果需要前缀,请选择 其他东西,以避免混淆。)
答案 1 :(得分:3)
如果存储实际对象(而不是引用或指针),是的,擦除对象时会破坏对象。
如果存储指针或引用,则不会销毁该对象,并且不会在指针上调用delete
。如果您希望自动执行此操作,则应使用智能指针(例如unique_ptr
或shared_ptr
,具体取决于您的行为)。
如果你不使用智能指针,那么你需要存储指针,并自己delete
对象(使用erase
后从map
中删除元素) 。
答案 2 :(得分:0)
第四次调用默认构造函数,因为
中的m[1]
std::cout << "erased test object: " << m[1].get_id() << std::endl;
将使用键&#34; 1&#34;构造一个新对象。这是因为这样的元素还没有存在于地图中 - 否则它只会返回已存在的对象。 (之前它确实存在,但是你在上面的行中删除它了!;])