map<int, int> m;
m[12] = 45; // 这是怎么实现的?
它只是返回了一个int&
,而且还不存在。为什么能赋值啊?
源码真的看不懂,……
1
pabupa OP (#`O′)喂?没人吗?
|
2
keygen88 2021-04-04 20:57:33 +08:00
重载了[]吧,
|
3
jmc891205 2021-04-04 21:00:51 +08:00 via iPhone
|
4
nightwitch 2021-04-04 21:07:30 +08:00
多看标准啊。标准明确告诉了如果 key 不存在,会先执行一次 insert 。 llvm 真正的实现在这里 https://github.com/llvm-mirror/libcxx/blob/78d6a7767ed57b50122a161b91f59f19c9bd0d19/include/__tree#L2126 它会先寻找内部是否存在这个值,如果不存在就会构造。 |
5
pabupa OP @nightwitch #4 那对于只读的情况来说,不就多余了吗?而且如果 V 不能无参构造的话,不久不能用了吗?
|
6
hello2060 2021-04-04 21:10:11 +08:00
已经忘了 c++了,这个你不是记住就行了吗?
它只是返回了一个 int&,而且还不存在 ------ 不存在你是怎么知道的,也许这个表达式在左边的时候会自动创建呢?你预设它不存在,所以无法赋值,但明明可以赋值,那不就说明你不存在的假设是错误的吗 |
9
ipwx 2021-04-04 21:13:49 +08:00 1
只读调用 const value_type& operator[](const key_type&) const
可变调用 value_type7 operator[](const key_type&) 函数末尾有没有修饰符 const,在 C++ 里面是两个不同的成员函数。 ==== 但是这里有个坑。如果你操作的是可变对象,你的 value_type 有默认构造函数,如果你使用 std::cout << m[key] << std::endl; 那么如果 key 不存在,在某些版本的 STL 真的会创建出这个对象。我就被坑过。 |
10
across 2021-04-04 21:15:06 +08:00
mapped_type& operator[] (key_type&& k);
C++11 里面加了个右值引用 |
11
across 2021-04-04 21:17:25 +08:00
@across 哦,答歪了。 这个取值不是 const 的,返回时内部已经创建过变量了。找标准解释都有说的。
http://www.cplusplus.com/reference/map/map/operator[]/ |
12
nightwitch 2021-04-04 21:17:37 +08:00 1
@pabupa https://en.cppreference.com/w/cpp/container/map/operator_at
仔细看标准吧。 1. 只读的时候 map 提供了 at 函数,对于不存在的 key 会抛异常 2. operaotr[]强制要求支持无参构造, 否则编译的时候会过不了编译。 |
13
pabupa OP |
14
mogg 2021-04-04 21:21:26 +08:00
只读用 find 判断迭代器,或者先 count 再取值
读取一次事实上要返回两个值,是否存在和值的内容。stl 的年代还没有 std::optional ( c++17 ),没有办法表示返回多个值,总不能 map[x] = y 给你报个 error 出来吧 |
15
nightl2018 2021-04-04 23:54:41 +08:00
只读用 find 先找一下存不存在。
``` auto it = m.find(x); if (it != m.end() ) cerr<<*it<<endl; else cerr<<"Not exist."<<endl; ``` |
16
nightl2018 2021-04-04 23:56:43 +08:00
初看觉得很怪,但是结合其他 STL 标准,就相当优美。比如 set:
``` set<int> s; if(s.insert(x).second == true) cerr<<"Insert success"<<endl; else cerr<<"Already exsit"<<endl; ``` |
17
Akiyu 2021-04-05 08:56:12 +08:00
好像很多人都已经回答了, 不过我还是说一下吧.
"它只是返回了一个 int&,而且还不存在。为什么能赋值啊?" "它只是返回了一个 int&" 是的, 它只是返回了一个 int&. 但这已经够了. int 是你 map value 的类型, 而 & 保证你的修改生效于 map 内部数据. "而且还不存在" 存在的, 对于 map 的 [] 重载而言, 当你访问的元素不存在时, 会创建一个(类型的零值). 而存在时, 会返回 valueType&. 所以无论如何, 都会有元素存在. (PS: 这里有个点需要注意, 当你想知道 map 中是否存在一个元素时, 你不能用 []. 因为这一定会存在, 你或许可以用这个类型的零值来判断是否是新创建的, 但这并不好, 更好的方式是: mapName.find(key) == maoName.end(); ) |
18
FrankHB 2021-04-05 11:21:55 +08:00
@ipwx 麻烦先记清楚 map::operator[] 要求 non-const 再来科普,谢谢。
怎么这么久都没个提出来 map::operator[] 早就改用 try_emplace 定义的? WG21 N4860 22.4.4.3 Element access [map.access] mapped_type& operator[](const key_type& x); 1 Effects: Equivalent to: return try_emplace(x).first->second; mapped_type& operator[](key_type&& x); 2 Effects: Equivalent to: return try_emplace(move(x)).first->second; 真折腾源码也行,给你个现成没到处 __ 的实现好了,C++11 下实现 C++17+ API,附加保证 incomplete value_type 能用: https://github.com/FrankHB/YSLib/blob/master/YBase/include/ystdex/map.hpp#L313 https://github.com/FrankHB/YSLib/blob/master/YBase/include/ystdex/tree.h#L1885 不过可能不如理解个外挂式 try_emplace 的逻辑顶用点: https://github.com/FrankHB/YSLib/blob/master/YBase/include/ystdex/container.hpp#L1039 |
19
opentrade 2021-04-05 13:08:09 +08:00 via Android
想到读研的时候有一次一个师弟问我为什么 Cpp 里函数里的局部变量外边不能访问。
|
20
unlighted 2021-04-06 11:43:49 +08:00 via Android
|
21
paxol 2021-06-04 01:39:48 +08:00
@pabupa std::string 以前用 COW 的时候也存在这么个问题,使用[]的时候无法判断作为左值还是右值,因此会导致不必要的 copy
|