std::映射运算符[]和size()的排序

std::map sequencing of operator[] and size()

本文关键字:排序 size 映射 运算符 std      更新时间:2023-10-16

我有一个std::map,并试图用对(name, id)填充它。id字段只是从映射的size()中生成的。这是一个简化版本:

#include <iostream>
#include <map>
struct A {
    std::string name;
    int id;
    A(const std::string &s) : name(s), id(-1) { }
};
class Database {
    std::map<std::string, int> ids;
public:
    void insert(A *item) {
        ids[item->name] = item->id = ids.size();
    }
    void dump() const {
        for (std::map<std::string, int>::const_iterator i = ids.begin(); i != ids.end(); i++)
            std::cout << i->second << ". " << i->first << std::endl;
    }
};
int main(int argc, char **agrv) {
    A a("Test");
    Database db;
    db.insert(&a);
    db.dump();
    return 0;
}

问题是不同的编译器对ids[item->name] = item->id = ids.size()部分的处理方式不同。Clang++产生

item->id = ids.size(); // First item gets 0
ids[item->name] = item->id;

当g++执行类似的操作时

ids.insert(std::pair<std::string, int>(item->name, 0));
item->id = ids.size(); // First item gets 1
ids[item->name] = item->id;

那么,这个代码是有效的(从STL的角度来看)还是像i = ++i + ++i一样邪恶?

ids[item->name] = item->id = ids.size();

在没有分隔两个调用的序列点的情况下,编译器可以自由地按照自己喜欢的任何顺序计算operator[]size()。不能保证size()会在operator[]之前被调用。

ids[item->name] = item->id = ids.size();更改为

item->id = ids.size();
ids[item->name] = item->id;