关于map的C++下标运算符

C++ subscript operator about map

最近被下标运算符弄糊涂了。例如 ,代码如下所示

#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  

然后调用赋值构造函数或拷贝构造函数? 输出是

user_defined constructor
default constructor
copy constructor
copy constructor
assign constructor

能否详细解释一下,非常感谢

当你写:

m[1] = A(1);

首先,地图会查找关键字为 1 的条目。如果找不到,它会尝试使用该键创建一个新条目,以及一个默认构造的 A 对象。由于您的 A class 不是默认可构造的,因此无法编译。

但假设情况并非如此,则返回对这个新创建的 A 对象的引用(或者对已经存在的对象的引用,如果找到密钥)。这一切都发生在 m[1] 表达式中。您语句的其余部分 = A(1) 创建一个新的 A 对象并将其分配给从 m[1].

返回的引用

如果您想知道调用了哪些函数,只需在调试器中对其设置断点即可。您会看到 m[1] = A(1); 按顺序调用

  1. 构造函数A(int)
  2. 默认构造函数A()(必须添加才能编译)
  3. A& operator=(const A& other)

所以发生的事情很清楚:它首先构造你的 A(1),然后在映射中搜索键 1,找不到它所以在上面插入一个默认的 A,最后替换它由你 A(1).

请注意,这发生在调试版本中。发布版本可以是 optimized 以避免上面的一些操作。在那些函数中添加打印是完全确定的。

如果您想尽量减少份数,请使​​用 m.emplace(1,1) 而不是 m[1] = A(1)。它只会调用构造函数A(int),既不会调用默认构造函数,也不会调用赋值运算符。