请牛人解释一下下头的拷贝构造函数和赋值构造函数

请牛人解释一下下面的拷贝构造函数和赋值构造函数

CClassObj obj1;         构造函数调用
CClassObj obj2 = obj1;  拷贝构造函数调用
CClassObj obj3;         构造函数调用
obj3 = obj1;            赋值函数调用

// 下面的三个调用麻烦解释一下,谢谢!
mapObj.insert( make_pair(1, obj1) );
拷贝构造函数调用
拷贝构造函数调用
析构函数调用
mapObj.insert( make_pair(1, std::move(obj1)) );
拷贝构造函数调用
拷贝构造函数调用
析构函数调用
析构函数调用
mapObj[0];
构造函数调用
拷贝构造函数调用
拷贝构造函数调用
析构函数调用
析构函数调用
请按任意键继续. . .

------解决方案--------------------
mapObj.insert( make_pair(1, obj1) );
拷贝构造函数调用
    make_pair创建一个pair临时对象,CClassObj被拷贝构造到pair对象中
拷贝构造函数调用
    pair对象被拷贝构造到mapObj中,pair的拷贝构造函数调用CClassObj的拷贝构造函数
析构函数调用
    pair临时对象析构,调用CClassObj的析构函数
mapObj.insert( make_pair(1, std::move(obj1)) );
    与上面类似。std::move将调用移动构造函数,但你没有定义移动构造函数,就由拷贝构造函数代替。
    比上面的多了一次析构,这很正常,因为与1对应的对象已经存在了,你的对象将替换原有对象,原有对象将被析构。

    这里本可以用拷贝赋值操作符完成的,但拷贝构造操作符没有被调用,这与你用的库中pair和map的实现有关,有两种可能:
    1:map::insert在key已经存在的情况下,就是先删除后添加,与用[1]=obj1的实现不同;
    2:pair是用拷贝构造和析构实现的赋值。凡是实现了无代价无异常的swap操作的对象都可以用拷贝构造函数+析构函数的方法实现拷贝赋值操作符。

  考虑到STL要求容器必需实现缺省构造和拷贝构造,而对拷贝赋值操作符没有要求,原因2成立的可能性很大。

mapObj[0];
构造函数调用
拷贝构造函数调用
拷贝构造函数调用
析构函数调用
析构函数调用
    这一步必然会调用缺省构造函数,因为operator[]要求在key不存在的情况下创建一个对象。其它两次析构都应该是在创建临时对象。不过这个operator[]产生了两个临时对象……不知道它是如何实现的,在我看来,operator[]应该返回引用或常量引用,应该不产生临时对象才对。