Re: [問題] 是否使用vector?

看板C_and_CPP (C/C++)作者 (髮箍)時間6年前 (2019/02/02 01:39), 6年前編輯推噓5(501)
留言6則, 5人參與, 6年前最新討論串2/2 (看更多)
※ 引述《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

02/02 13:40, 6年前 , 1F
感謝整理與分享
02/02 13:40, 1F

02/02 18:02, 6年前 , 2F
題外話 請問如何存取vector string裡面的字元?
02/02 18:02, 2F

02/02 18:22, 6年前 , 3F
s1[0][0]這樣吧?樓上
02/02 18:22, 3F

02/02 18:57, 6年前 , 4F
我試試看 謝謝樓上
02/02 18:57, 4F
比較好的方式是: 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)來存取容器元素, 也可以減少對容器介面的依賴.

02/03 01:43, 6年前 , 5F
最近的文都太專業了吧
02/03 01:43, 5F
※ 編輯: poyenc (123.193.76.85), 02/03/2019 17:30:32

02/03 19:42, 6年前 , 6F
剛轉回C/CPP版真D沒讓我失望XDDD 推個
02/03 19:42, 6F
文章代碼(AID): #1SL8G_sn (C_and_CPP)
討論串 (同標題文章)
本文引述了以下文章的的內容:
完整討論串 (本文為第 2 之 2 篇):
文章代碼(AID): #1SL8G_sn (C_and_CPP)