最近,我对下标操作员对地图感到困惑。例如 ,代码如下所示
#include <map>
class A{
public:
int a;
A(){cout << "default constructor" <<endl;}
A(int a){
cout << "user_defined constructor" <<endl;
this->a = a;
}
A(const A& tmp){
cout << "copy constructor" <<endl;
this->a = tmp.a;
}
A& operator= (const A& tmp){
cout << "assign constructor" <<endl;
this->a = tmp.a;
return *this;
}
};
int main(){
std::map<int, A> m;
m[1] = A(1); // error occur right?
m.insert (make_pair(1,A(1))); // ok
}
我想知道编写代码时发生了什么。
m[1] = A(1); // it will first make a empty pair ? right?
m.insert (make_pair(1,A())); // here call default constructor
然后调用Assignment构造函数或复制构造函数? 输出是
user_defined constructor
default constructor
copy constructor
copy constructor
assign constructor
你能否向我解释一下细节,非常感谢。
答案 0 :(得分:3)
当你写:
m[1] = A(1);
首先,地图会查找密钥为1
的条目。如果它找不到,则它会尝试使用该键创建一个新条目,以及一个默认构造的A
对象。由于您的A
类不是默认可构造的,因此无法编译。
但假设情况并非如此,则返回对此新创建的A
对象的引用(或对已存在的对象的引用,如果找到该键)。这一切都发生在m[1]
表达式上。声明的其余部分= A(1)
会创建一个新的A
对象,并将其分配给从m[1]
返回的引用。
答案 1 :(得分:1)
如果您想知道调用哪些函数,只需在调试器中设置它们的断点即可。您会看到m[1] = A(1);
按顺序调用
A(int)
A()
(必须添加以进行编译)A& operator=(const A& other)
所以发生的事情非常清楚:它首先构造你的A(1)
,然后在地图中搜索键1,找不到它,因此在其上插入一个默认的A
,最后将其替换为你的A(1)
。
介意这发生在调试版本上。发布版本可以optimized以避免上述某些操作。在这些功能中添加打印件以完全确定。
如果您想减少副本数量,请使用m.emplace(1,1)
代替m[1] = A(1)
。它只会调用构造函数A(int)
,既不是默认构造函数,也不是赋值运算符。