2016-05-05 69 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,相應密鑰的新值在那裏存在。

相關問題