menhirLib
std::vector
是否有理由只返回引用而不是插入新元素? operator[]
的cppreference.com页面显示here
与
vector::operator
不同,此运算符从不在容器中插入新元素。
std::map::operator[]
says
"返回对映射到等效于key的键的值的引用,如果此类键尚不存在则执行插入。"
为什么不能通过调用map::operator[]
或vector::operator[]
来实现vector::push_back
vector::insert
调用map::operator[]
的方式来实现insert(std::make_pair(key, T())).first->second;
?
答案 0 :(得分:7)
非常简单:因为它没有意义。你期待什么
std::vector<int> a = {1, 2, 3};
a[10] = 4;
要做什么?即使您指定索引10,也要创建第四个元素?创建元素3到10并返回对最后一个的引用?两者都不会特别直观。
如果您确实希望使用operator[]
而不是push_back
使用值填充向量,则可以在向量上调用resize
以在设置之前创建元素。
编辑:或者,如果你真的想拥有一个关联容器,除了排序之外索引很重要,std::map<int, YourData>
实际上可能更有意义。
答案 1 :(得分:1)
地图和矢量是完全不同的概念。映射是“关联容器”,而向量是“序列容器”。描述差异超出了这个答案的范围,尽管在最浅层的情况下,地图通常被实现为红黑树,而向量是C风格数组上的复杂包装(连续存储的元素)记忆)。
如果要检查元素是否已存在,则需要调整整个容器的大小。但是如果您决定删除该元素会发生什么?您如何处理刚刚创建的条目?有了地图:
std::map<int, int> m;
m[1] = 1;
m.erase(m.begin());
这是一个持续的操作。
使用向量:
std::vector<int> v;
// ... initialize some values between 25 and 100
v[100] = 1;
v.erase(v.begin() + 25, v.end());
这是线性操作。这对地图来说非常低效(相对而言)。虽然这是一个人为的例子,但不难想象在其他场景中这会如何爆炸。至少,大多数人会尽力避免operator[]
这本身就是一种成本(维护和代码复杂性)。
答案 2 :(得分:0)
std :: vector的operator []有没有理由只返回一个引用而不是插入一个新元素?
std::vector::operator[]
以类似数组的方式实现,因为std::vector
是一个序列容器(即类似数组)。用于整数类型的标准数组不能超出范围。同样,也不允许使用索引超出向量长度的std::vector::operator[]
进行访问。所以,是的,它没有按照你的要求实现的原因是因为在其他任何情况下,C ++中的数组都是这样的。
std::map::operator[]
不是序列容器。它的语法使其类似于其他语言中的关联数组。就C ++(及其前身C)而言,map::operator[]
只是语法糖。它是operator[]
家族的“黑羊”,不是 std::vector::operator[]
。
C ++规范中有趣的部分是使用std::map::operator[]
访问具有不存在的键的地图,向地图添加元素。因此,
#include <iostream>
#include <map>
int main(void) {
std::map<char, int> m;
m['a'] = 1;
std::cout << "m['a'] == " << m['a'] << ", m.size() == " << m.size() << std::endl;
std::cout << "m['b'] == " << m['b'] << ", m.size() == " << m.size() << std::endl;
}
结果:
m['a'] == 1, m.size() == 1
m['b'] == 0, m.size() == 2
另请参阅:Difference between map[] and map.at in C++?:
如果密钥不存在,[
map::at
]会抛出异常,如果元素不存在,则find
会返回aMap.end()
,operator[]
值如果没有值,则初始化相应键的新值。