2016-05-05 64 views
5

是否有任何理由让std::vectoroperator[]只返回一个引用而不是插入一个新的元素?对于vector::operator的cppreference.com页说:here为什么不是vector :: operator []实现类似于map :: operator []?

不像std::map::operator[],该运营商从来没有插入一个新的元素到容器中。

虽然map::operator[]says

在网页“返回到被映射到一键等同于键的值的基准,如果这样的键不存在进行中的插入”。

为什么不能vector::operator[]致电vector::push_backvector::insert怎么样map::operator[]电话insert(std::make_pair(key, T())).first->second;实施?

+3

'std :: map :: operator []'的方式实际上已经导致了足够的混乱。 UB适合'std :: vector'访问越界。 –

+0

想象一下,如果我们写'some_vector [1000]'而'some_vector'的大小是10时会发生什么。那么,我不知道中间的990条目想象什么。 –

+0

@NickyC:但是地图有同样的问题! –

回答

7

很简单:因为它没有意义。你期待什么

std::vector<int> a = {1, 2, 3}; 
a[10] = 4; 

要做什么?即使您指定了索引10,也要创建第四个元素?创建元素3到10并返回一个引用到最后一个?这两者都不会特别直观。

如果您确实想要使用operator[]而不是push_back填充具有值的矢量,则可以在矢量上调用resize以在设置它们之前创建元素。

编辑:或者,如果您真的想拥有一个关联容器,其中索引除了排序之外很重要,std::map<int, YourData>实际上可能更有意义。

+2

值得强调一下关键点:对于'map',运算符至多在给定键处插入一个元素。对于'vector',你还必须在其他索引处插入* other *元素。 –

+0

+1。另外值得一提的是,C++认为性能问题比许多语言(例如Java)更多。这就是为什么'vector :: operator []'不执行边界检查的原因;如果你觉得你需要它们,你可以手动选择它们,但是C++希望在这里没有任何开销。即使在矢量中插入不存在的元素也是有意义的,它会直接与性能目标相矛盾。正如对边界检查的渴望一样,如果您希望为您插入元素,则可以在矢量之上自己构建一个更高级别的类并选择加入。 – GManNickG

+0

@GManNickG所以基本上,如果我想插入不存在的元素,那么我被迫使用一个映射,因为vector是一个序列容器? – 1337ninja

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[]本身的成本(维护和代码复杂度)。

+0

+1,因为你触及了矢量和指针基于两个独立数据结构的事实。向量是非常花哨的数组,而地图是基于指针。如果您需要使用迭代器进行搜索,则地图非常棒。虽然Vectors很棒,如果你知道你需要什么元素在数组中。 – Caperneoignis

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[]值初始化如果没有v,相应密钥的新值在那里存在。

相关问题