为什么不能实现vector :: operator []类似于map :: operator []?

时间:2016-05-05 02:06:11

标签: c++ dictionary vector stl

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;

3 个答案:

答案 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[] 值如果没有值,则初始化相应键的新值。