从std :: map中删除对象时销毁对象

时间:2013-08-07 08:29:09

标签: c++ std stdmap erase

当我从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

问题是:

  1. 为什么这么多次默认构造函数被调用,当时我只是 使用我自己的构造函数创建3个对象?
  2. 我可以,基于 这个例子说,每次我从中删除任何对象 std::map,它的析构函数被称为?这是一般的行为吗? std::map?我找不到这个信息。
  3. 如果我存储指向对象的指针(我使用'new'运算符创建它们)怎么办?何时调用delete

3 个答案:

答案 0 :(得分:6)

std::map存储您插入的对象的副本。当。。。的时候 对象被删除,这是被破坏的副本。所以 在m[1] = t1;之后,有两个相同的实例 CTestMapt1和地图中的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_ptrshared_ptr,具体取决于您的行为)。

如果你不使用智能指针,那么你需要存储指针,并自己delete对象(使用erase后从map中删除元素) 。

答案 2 :(得分:0)

第四次调用默认构造函数,因为

中的m[1]
std::cout << "erased test object: " << m[1].get_id() << std::endl;

将使用键&#34; 1&#34;构造一个新对象。这是因为这样的元素还没有存在于地图中 - 否则它只会返回已存在的对象。 (之前它确实存在,但是你在上面的行中删除它了!;])