看板 C_and_CPP 關於我們 聯絡資訊
※ 引述《clonsey1314 (Clonsey)》之銘言: : 最近剛接觸vector, 很方便, 省了很多初始化的工作 : 程式碼也變得簡潔多, 也較好維護 : 但是同時也降低的程式的效能(很明顯) : 請問若沒有要做太多複雜的增刪,是否繼續使用array或pointer就好? : 程式碼裡同時有vector和pointer/array混雜這樣的coding style會不會不好? : 謝謝 一般在 std::vector 和 C array 間作選擇的考量點主要在元素個數的 決定時機: 如果元素個數在編譯時期可以決定, 當然使用 C array 或 std::array; 如果只能在執行時期決定, 才需要考慮 std::vector, 但 也不是預設就使用 STL 容器, 端看你的使用情境. 簡單舉個例子: 假如我們現在需要一塊連續記憶體來儲存班上同學的期 末考成績, 班上同學的數目已知是 50 位, 分數是非負整數, 就可以用 std::array 來定義: using score_type = unsigned; std::array<score_type, 50> scores; 然後可能因為效能需求, 或到某個時機點才需要將這塊記憶體配置出來 (lazy initialization), 可以考慮 std::unique_ptr + std::array: std::unique_ptr<std::array<score_type, 50>> scores; 需要注意的是, 這裡和 std::unique_ptr<score_type[]> 的差別在於 元素個數的決定時機, 如果想使用後者, 代碼的長相需要像這樣: std::size_t n; std::cin >> n; auto scores = std::make_unique<score_type[]>(n); 兩者表達的語意完全不一樣. 另外 std::vector 雖然簡化了物件初始 化及複製, 但其附帶的可變長度性質, 也不適合用來描述上面的問題. 所以用什麼型別不是問題, 問題是有沒有用對型別. 最後整理給你作參 考: (考慮 owning 語意) 元素個數在編譯時期決定: 不需要改變大小: std::array<T, N> 元素個數在執行時期決定: 需要改變大小: STL container 不需要改變大小: std::unique_ptr<T[]> 選用何種 STL 容器就看需要哪些操作 (存取方式、存取成本、新增/刪 除元素的位置等..) 假如會在後端以外的地方新增元素, std::vector 就不是好的選擇. -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 123.193.76.85 ※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1549042751.A.DB1.html
ilikekotomi: 感謝整理與分享 02/02 13:40
tomsawyer: 題外話 請問如何存取vector string裡面的字元? 02/02 18:02
achicn3: s1[0][0]這樣吧?樓上 02/02 18:22
tomsawyer: 我試試看 謝謝樓上 02/02 18:57
比較好的方式是: using std::next; const std::vector<std::string> vs{"hello"s, "world"s}; const auto idx = 1z; // or const std::ptrdiff_t idx = 1; in pre-c++20 [[assert: idx < size(vs)]]; const std::string_view sv = *next(begin(vs), idx); [[assert: sv[1] == 'o']]; 雖然 std::vector 就有提供 operator[] 用來存取元素, 但並不是所有 的 STL 容器都有提供相同的介面, 當你寫下 vs[..] 的時候, 增加了對 容器的需求(requirement), 導致抽換容器實作的時候為了滿足(satisfy) 原本的需求必須實作這些介面. 不管是 generic programming 或是想要提供復用性更高的程式碼, 對容 器的操作盡可能地侷限在迭代器(iterator) 上是比較好的, 使用比較通 用的介面未來擴充性也比較高. 譬如上面這個例子, 若把 next()呼叫改 為: begin(vs) + idx // bad example 這個操作需要迭代器滿足 RandomAccessIterator 概念(concept), 因為 std::vector 本身滿足 ContiguousContainer, 很容易就會使用到不必要 的操作, 是比較不好的用法. 使用 begin() 讓 ADL(argument dependent lookup) 尋找合適的呼叫 (包含自定義函式), 多了 next() 間接呼叫讓 ForwardIterator 也能當作引數, 這段碼的復用性就大大地提高了. 最後建議透過 std::span 或 std::string_view 甚至是 ranges library 裏的適配器(adaptor)來存取容器元素, 也可以減少對容器介面的依賴.
allensheng: 最近的文都太專業了吧 02/03 01:43
※ 編輯: poyenc (123.193.76.85), 02/03/2019 17:30:32
leoloveivy: 剛轉回C/CPP版真D沒讓我失望XDDD 推個 02/03 19:42