ํฌ์ŠคํŠธ

CS โ€” vector vs list

CS โ€” vector vs list

๐Ÿ“• 04/28 โ€” std::vector vs std::list ๋ชจ์˜๋ฉด์ ‘ ์ค€๋น„

๋‚ด์ผ(04/29) ๋ชจ์˜๋ฉด์ ‘ ์ฃผ์ œ: โ€œstd::vector์™€ std::list์˜ ์ฐจ์ด์ ์€ ๋ฌด์—‡์ธ๊ฐ€์š”? ์–ธ์ œ ์–ด๋–ค ๊ฑธ ์“ฐ๋‚˜์š”?โ€ ๋ฉ”๋ชจ๋ฆฌ ๋ ˆ์ด์•„์›ƒ โ†’ ์‹œ๊ฐ„ ๋ณต์žก๋„ ํ•จ์ • โ†’ CPU ์บ์‹œ(โ˜… ํ•ต์‹ฌ) โ†’ iterator ๋ฌดํšจํ™”/์˜ˆ์™ธ ์•ˆ์ „์„ฑ โ†’ ์–ธ์ œ list๋ฅผ ์จ์•ผ ํ•˜๋‚˜ โ†’ TArray/UE ์ปจํ…Œ์ด๋„ˆ ๊ผฌ๋ฆฌ์งˆ๋ฌธ ์—ฐ๊ฒฐ ๋‹ค๋ฆฌ


ํ•™์Šต ์˜์—ญ ์ „ํ™˜์  โ€” ์–ธ์–ด ๋ฌธ๋ฒ•์—์„œ STL + ์‹œ์Šคํ…œ์œผ๋กœ

์ง€๊ธˆ๊นŒ์ง€์˜ ํ๋ฆ„์„ ์ž ๊น ์ •๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

1
2
3
4
5
6
05~10๋ฒˆ  vtable / virtual ์†Œ๋ฉธ์ž / ํฌ์ธํ„ฐ / ๋Œ•๊ธ€๋ง      โ€” C++ ์–ธ์–ด ์˜๋ฏธ๋ก  (๋‹คํ˜•์„ฑยท๋ฉ”๋ชจ๋ฆฌ)
11๋ฒˆ     ์Šค๋งˆํŠธ ํฌ์ธํ„ฐ (unique/shared/weak)             โ€” RAII ๊ธฐ๋ฐ˜ ์ž์› ๊ด€๋ฆฌ
12๋ฒˆ     ๊ฐ์ฒด ๋ณต์‚ฌ ๊ธˆ์ง€ / Rule of N / move-only         โ€” C++ ์–ธ์–ด ๋ฌธ๋ฒ• (ํŠน๋ณ„ ๋ฉค๋ฒ„ ํ•จ์ˆ˜)
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
13๋ฒˆ     std::vector vs std::list                       โ€” STL ์ปจํ…Œ์ด๋„ˆ + ์‹œ์Šคํ…œ(CPU ์บ์‹œ) โ˜…
์ดํ›„     ํ•ด์‹œ๋งต / ์ •๋ ฌ / ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น์ž / ์Šค๋ ˆ๋“œ ๋ชจ๋ธ ๋“ฑ โ€” STL ยท OS ยท HW ์˜์—ญ

12๋ฒˆ๊นŒ์ง€๊ฐ€ โ€œ์ด ์ฝ”๋“œ๊ฐ€ ์–ด๋–ป๊ฒŒ ์ปดํŒŒ์ผ๋˜๊ณ  ์–ด๋–ค ์˜๋ฏธ์ธ๊ฐ€โ€ ์˜€๋‹ค๋ฉด, 13๋ฒˆ๋ถ€ํ„ฐ๋Š” โ€œ์ด ์ž๋ฃŒ๊ตฌ์กฐ๊ฐ€ ์‹ค์ œ ํ•˜๋“œ์›จ์–ด์—์„œ ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๊ณ  ์™œ ๋น ๋ฅธ/๋А๋ฆฐ๊ฐ€โ€ ๋กœ ์งˆ๋ฌธ ์ถ•์ด ๋ฐ”๋€๋‹ˆ๋‹ค.

ํŠนํžˆ ์ด ์ฃผ์ œ์˜ ํ•ต์‹ฌ์€ โ€œ์ด๋ก  ์‹œ๊ฐ„ ๋ณต์žก๋„๊ฐ€ ๊ฐ™์•„๋„ ์บ์‹œ ์นœํ™”์„ฑ์ด ์‹ค์ œ ์„ฑ๋Šฅ์„ ๊ฒฐ์ •ํ•œ๋‹คโ€ ์ž…๋‹ˆ๋‹ค. O(1) < O(n)์ด๋ผ๋Š” ๊ต๊ณผ์„œ ๋‹ต์ด ํ˜„๋Œ€ CPU์—์„œ ์ •๋ฐ˜๋Œ€๋กœ ๋’ค์ง‘ํžˆ๋Š” ๊ฐ€์žฅ ์œ ๋ช…ํ•œ ์‚ฌ๋ก€๊ฐ€ ๋ฐ”๋กœ vector vs list์ž…๋‹ˆ๋‹ค.


๋ชจ์˜๋ฉด์ ‘ ๋‹ต๋ณ€

std::vector์™€ std::list๋Š” ๋ชจ๋‘ ์‹œํ€€์Šค ์ปจํ…Œ์ด๋„ˆ์ด์ง€๋งŒ ๋ฉ”๋ชจ๋ฆฌ ๋ ˆ์ด์•„์›ƒ์ด ์ •๋ฐ˜๋Œ€์ž…๋‹ˆ๋‹ค. vector๋Š” ์—ฐ์† ๋ฉ”๋ชจ๋ฆฌ(contiguous) ๋™์  ๋ฐฐ์—ด๋กœ, capacity๊ฐ€ ๋ถ€์กฑํ•˜๋ฉด ๋ณดํ†ต 1.5~2๋ฐฐ๋กœ ์žฌํ• ๋‹นํ•˜๋ฉด์„œ ๋ชจ๋“  ์›์†Œ๋ฅผ ์ƒˆ ๋ฒ„ํผ๋กœ ์˜ฎ๊น๋‹ˆ๋‹ค. list๋Š” ์ด์ค‘ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋กœ ๊ฐ ๋…ธ๋“œ๊ฐ€ ํž™์— ๋”ฐ๋กœ ํ• ๋‹น๋˜๊ณ  prev/next ํฌ์ธํ„ฐ๋กœ ์—ฐ๊ฒฐ๋ฉ๋‹ˆ๋‹ค.

์ด๋ก  ์‹œ๊ฐ„ ๋ณต์žก๋„๋งŒ ๋ณด๋ฉด list๊ฐ€ ์œ ๋ฆฌํ•œ ๋“ฏ ๋ณด์ž…๋‹ˆ๋‹ค. ์ค‘๊ฐ„ ์‚ฝ์ž…์ด vector๋Š” O(n), list๋Š” O(1)์ด๋‹ˆ๊นŒ์š”. ํ•˜์ง€๋งŒ ์‹ค์ธก ์„ฑ๋Šฅ์€ ๊ฑฐ์˜ ํ•ญ์ƒ vector๊ฐ€ ์••์Šนํ•ฉ๋‹ˆ๋‹ค. ์ด์œ ๋Š” CPU ์บ์‹œ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. CPU๋Š” ๋ฉ”๋ชจ๋ฆฌ๋ฅผ 64๋ฐ”์ดํŠธ ์บ์‹œ ๋ผ์ธ ๋‹จ์œ„๋กœ ๊ฐ€์ ธ์˜ค๊ณ , ํ•œ ๋ฒˆ ๊ฐ€์ ธ์˜จ ๋ผ์ธ ์•ˆ์˜ ๋ฐ์ดํ„ฐ๋Š” L1 ๊ธฐ์ค€ 1ns ์ •๋„๋กœ 100๋ฐฐ ๋น ๋ฅด๊ฒŒ ์ ‘๊ทผ๋ฉ๋‹ˆ๋‹ค. vector๋Š” ์›์†Œ๊ฐ€ ์—ฐ์†์ด๋ผ ํ•œ ์บ์‹œ ๋ผ์ธ์— ์—ฌ๋Ÿฌ ๊ฐœ๊ฐ€ ๋™์‹œ์— ๋“ค์–ด์˜ค๊ณ  ํ•˜๋“œ์›จ์–ด ํ”„๋ฆฌํŽ˜์ฒ˜๊ฐ€ ๋‹ค์Œ ๋ผ์ธ์„ ๋ฏธ๋ฆฌ ๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค. list๋Š” ๋…ธ๋“œ๊ฐ€ ํž™ ์—ฌ๊ธฐ์ €๊ธฐ ํฉ์–ด์ ธ ์žˆ์–ด ๋งค ๋…ธ๋“œ ์ ‘๊ทผ๋งˆ๋‹ค ์บ์‹œ ๋ฏธ์Šค๊ฐ€ ๋‚˜๊ณ  prefetch๊ฐ€ ๋™์ž‘ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. 1M๊ฐœ ์ •์ˆ˜ ์ˆœํšŒ ๋ฒค์น˜๋งˆํฌ์—์„œ vector๋Š” ์•ฝ 1ms, list๋Š” ์•ฝ 100ms โ€” ์ด๋ก ์€ ๊ฐ™์€๋ฐ ์‹ค์ธก์€ 100๋ฐฐ ์ฐจ์ด๊ฐ€ ๋‚ฉ๋‹ˆ๋‹ค.

iterator ๋ฌดํšจํ™” ๊ทœ์น™๋„ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. vector๋Š” ์žฌํ• ๋‹น์ด ์ผ์–ด๋‚˜๋ฉด ๋ชจ๋“  iterator๊ฐ€ ๋ฌดํšจํ™”๋˜๊ณ , ์ค‘๊ฐ„ insert/erase๋Š” ๊ทธ ์œ„์น˜ ์ดํ›„๊ฐ€ ๋ฌดํšจํ™”๋ฉ๋‹ˆ๋‹ค. list๋Š” ์‚ญ์ œ๋œ ๋…ธ๋“œ ์ž์‹ ๋งŒ ๋ฌดํšจํ™”๋˜๊ณ  ๋‚˜๋จธ์ง€๋Š” ์•ˆ์ „ํ•ด์„œ splice/merge ๊ฐ™์€ ๋…ธ๋“œ ์žฌ๋ฐฐ์น˜ ์—ฐ์‚ฐ์ด ๊น”๋”ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒŒ list์˜ ๊ฑฐ์˜ ์œ ์ผํ•œ ์‹ค์šฉ์  ๊ฐ•์ ์ž…๋‹ˆ๋‹ค.

๊ฒฐ๋ก ์ ์œผ๋กœ ํ˜„๋Œ€ ํ•˜๋“œ์›จ์–ด์—์„œ list๋Š” ๊ฑฐ์˜ ํ•ญ์ƒ ์ž˜๋ชป๋œ ์„ ํƒ์ž…๋‹ˆ๋‹ค. Stroustrup์ด ์ง์ ‘ ๊ฐ•์—ฐ์—์„œ โ€œstd::vector๋ฅผ ์“ฐ์„ธ์š”. ์˜์‹ฌ์Šค๋Ÿฌ์šฐ๋ฉด ๊ทธ๋ž˜๋„ vector๋ฅผ ์“ฐ์„ธ์š”โ€๋ผ๊ณ  ๊ถŒ๊ณ ํ•˜๋Š” ๊ฒƒ๋„ ์ด ์ด์œ ์ž…๋‹ˆ๋‹ค. list๊ฐ€ ์ •๋‹นํ™”๋˜๋Š” ๋“œ๋ฌธ ์ผ€์ด์Šค๋Š” ๋งค์šฐ ํฐ ๊ฐ์ฒด + ์žฆ์€ ์ค‘๊ฐ„ splice + iterator ์•ˆ์ •์„ฑ์ด ์ ˆ๋Œ€์ ์œผ๋กœ ํ•„์š”ํ•œ ๊ฒฝ์šฐ๋ฟ์ž…๋‹ˆ๋‹ค. ๋‘˜์˜ ์ ˆ์ถฉ์•ˆ์ด ํ•„์š”ํ•˜๋ฉด ์ฒญํฌ ๊ธฐ๋ฐ˜์ธ std::deque๋ฅผ ๋ณด๋Š” ๊ฒŒ ๋ณดํ†ต ๋” ํ•ฉ๋ฆฌ์ ์ž…๋‹ˆ๋‹ค.

์–ธ๋ฆฌ์–ผ์—์„œ๋Š” ์ด ์ฒ ํ•™์ด ๋” ๊ฐ•ํ•˜๊ฒŒ ๋“œ๋Ÿฌ๋‚ฉ๋‹ˆ๋‹ค. TArray๊ฐ€ vector ๋Œ€์‘์œผ๋กœ 1๊ธ‰ ์‹œ๋ฏผ์ด๊ณ , std::list์— ์ง์ ‘ ๋Œ€์‘ํ•˜๋Š” ์ž๋ฃŒ๊ตฌ์กฐ๋Š” ์˜๋„์ ์œผ๋กœ 1๊ธ‰์œผ๋กœ ๋‘์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. TLinkedList/TDoubleLinkedList๋Š” ์žˆ์ง€๋งŒ ๊ฐ€๋ฒผ์šด ํ—ฌํผ ์ˆ˜์ค€์ž…๋‹ˆ๋‹ค. ์บ์‹œ ์นœํ™”์„ฑ์ด ๊ฒŒ์ž„ ์—”์ง„ ์„ฑ๋Šฅ์— ์ง๊ฒฐ๋˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.


ํ•ต์‹ฌ ๊ฐœ๋…

๋ถ„๋ฅ˜ํ‚ค์›Œ๋“œํ•œ ์ค„ ์ •์˜
์ปจํ…Œ์ด๋„ˆ ๊ธฐ๋ณธstd::vector์—ฐ์† ๋ฉ”๋ชจ๋ฆฌ ๋™์  ๋ฐฐ์—ด. ๋ push_back amortized O(1)
ย std::list์ด์ค‘ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ. ๋…ธ๋“œ๊ฐ€ ํž™์— ๋ถ„์‚ฐ, prev/next ํฌ์ธํ„ฐ
ย std::forward_list๋‹จ๋ฐฉํ–ฅ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ. ๋…ธ๋“œ๋‹น 8๋ฐ”์ดํŠธ ์ ˆ์•ฝ
ย std::deque์ฒญํฌ ๊ธฐ๋ฐ˜ ๋”๋ธ”์—”๋“œ ํ. push_front/back ๋ชจ๋‘ O(1)
ย std::array๊ณ ์ • ํฌ๊ธฐ ๋ฐฐ์—ด. ์ปดํŒŒ์ผ ํƒ€์ž„ size, ์Šคํƒ ํ• ๋‹น ๊ฐ€๋Šฅ
๋ฉ”๋ชจ๋ฆฌ ๋ ˆ์ด์•„์›ƒ์—ฐ์† ๋ฉ”๋ชจ๋ฆฌ (Contiguous)์›์†Œ๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์ƒ ์ธ์ ‘. vectorยทarray์˜ ํ•ต์‹ฌ ํŠน์„ฑ
ย ๋ถ„์‚ฐ ํ• ๋‹น (Scattered)๋…ธ๋“œ๋งˆ๋‹ค ๋ณ„๋„ ํž™ ํ• ๋‹น. list์˜ ํ•ต์‹ฌ ํŠน์„ฑ
ย capacity vs sizesize: ์‹ค์ œ ์›์†Œ ์ˆ˜, capacity: ํ• ๋‹น๋œ ์Šฌ๋กฏ ์ˆ˜
ย ์žฌํ• ๋‹น (Reallocation)size > capacity ์‹œ ์ƒˆ ๋ฒ„ํผ ํ• ๋‹น + ๊ธฐ์กด ์›์†Œ ์ด์ „
ย ์„ฑ์žฅ ์ธ์ž (Growth Factor)๋ณดํ†ต 1.5x(MSVC) ~ 2x(libstdc++) โ€” amortized O(1) ๋ณด์žฅ
์‹œ๊ฐ„ ๋ณต์žก๋„amortized O(1)ํ‰๊ท ์ ์œผ๋กœ O(1)์ด์ง€๋งŒ ๊ฐ€๋” O(n) ๋น„์šฉ. ๋ถ„ํ•  ์ƒํ™˜ ๋ถ„์„
ย ์ž„์˜ ์ ‘๊ทผ (Random Access)v[i]๋กœ ์ฆ‰์‹œ i๋ฒˆ์งธ ์›์†Œ. vector O(1), list O(n)
ย ์ˆœ์ฐจ ์ ‘๊ทผ (Sequential Access)iterator++๋กœ ์ˆœํšŒ โ€” list๋„ O(n)์ด์ง€๋งŒ ์บ์‹œ ๋ฏธ์Šค๋กœ ์‹ค์ธก ๋А๋ฆผ
CPU ์บ์‹œ โ˜…๋ฉ”๋ชจ๋ฆฌ ๊ณ„์ธต (Memory Hierarchy)๋ ˆ์ง€์Šคํ„ฐ โ†’ L1 โ†’ L2 โ†’ L3 โ†’ DRAM (์†๋„ ๊ฒฉ์ฐจ 100๋ฐฐ)
ย L1 ์บ์‹œ~32KB, ~1ns ์ ‘๊ทผ. ์ฝ”์–ด๋‹น ์ „์šฉ
ย L2 ์บ์‹œ~256KB, ~3ns ์ ‘๊ทผ. ์ฝ”์–ด๋‹น ์ „์šฉ(๋ณดํ†ต)
ย L3 ์บ์‹œ~8MB, ~12ns ์ ‘๊ทผ. ์ฝ”์–ด ๊ฐ„ ๊ณต์œ 
ย DRAMGB ๋‹จ์œ„, ~100ns ์ ‘๊ทผ. L1 ๋Œ€๋น„ 100๋ฐฐ ๋А๋ฆผ
ย ์บ์‹œ ๋ผ์ธ (Cache Line)๋ฉ”๋ชจ๋ฆฌ ์ „์†ก ๋‹จ์œ„. ๋ณดํ†ต 64๋ฐ”์ดํŠธ (x86_64)
ย ๊ณต๊ฐ„ ์ง€์—ญ์„ฑ (Spatial Locality)๊ฐ€๊นŒ์šด ์ฃผ์†Œ์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ๊ณง ์‚ฌ์šฉ๋  ํ™•๋ฅ ์ด ๋†’์Œ
ย ์‹œ๊ฐ„ ์ง€์—ญ์„ฑ (Temporal Locality)ํ•œ ๋ฒˆ ์“ด ๋ฐ์ดํ„ฐ๋ฅผ ๊ณง ๋‹ค์‹œ ์“ธ ํ™•๋ฅ ์ด ๋†’์Œ
ย ํ•˜๋“œ์›จ์–ด ํ”„๋ฆฌํŽ˜์ฒ˜ (Prefetcher)์ˆœ์ฐจ ์ ‘๊ทผ ํŒจํ„ด ๊ฐ์ง€ โ†’ ๋‹ค์Œ ์บ์‹œ ๋ผ์ธ ์ž๋™ ๋กœ๋“œ
ย ์บ์‹œ ๋ฏธ์Šค (Cache Miss)L1/L2/L3์— ์—†์–ด์„œ ๋” ๋А๋ฆฐ ๊ณ„์ธต๊นŒ์ง€ ๋‚ด๋ ค๊ฐ€์•ผ ํ•˜๋Š” ์ƒํ™ฉ
ย ์บ์‹œ ์นœํ™”์„ฑ (Cache Friendliness)์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ์บ์‹œ ๋™์ž‘์— ์ž˜ ๋งž๋Š” ์ •๋„. ์‹ค์ธก ์„ฑ๋Šฅ ๊ฒฐ์ •
iterator ๋ฌดํšจํ™”์žฌํ• ๋‹น ๋ฌดํšจํ™”vector capacity ์ฆ๊ฐ€ ์‹œ ๋ชจ๋“  iterator/ํฌ์ธํ„ฐ/์ฐธ์กฐ ๋ฌดํšจํ™”
ย ๋ถ€๋ถ„ ๋ฌดํšจํ™”vector insert/erase ์‹œ ํ•ด๋‹น ์œ„์น˜ ์ดํ›„๋งŒ ๋ฌดํšจํ™”
ย ๋…ธ๋“œ ์•ˆ์ •์„ฑ (Node Stability)list/map์€ ์‚ญ์ œ๋œ ๋…ธ๋“œ๋งŒ ๋ฌดํšจํ™” โ€” splice/merge ์•ˆ์ „
๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ๋…ธ๋“œ ์˜ค๋ฒ„ํ—ค๋“œlist ๋…ธ๋“œ = ๋ฐ์ดํ„ฐ + prev 8B + next 8B + ํž™ ํ—ค๋”
ย ํ• ๋‹น์ž ํ˜ธ์ถœ ํšŸ์ˆ˜vector๋Š” 1ํšŒ, list๋Š” NํšŒ(๋…ธ๋“œ๋งˆ๋‹ค)
ย ๋ฉ”๋ชจ๋ฆฌ ๋‹จํŽธํ™” (Fragmentation)list๋Š” ์ž‘์€ ๋ธ”๋ก์„ ์ž์ฃผ ํ• ๋‹น โ†’ ๋‹จํŽธํ™” ์œ ๋ฐœ
๊ถŒ์žฅ ๋ฃฐโ€œVector firstโ€ ๋ฃฐStroustrupยทSutter โ€” ์˜์‹ฌ์Šค๋Ÿฌ์šฐ๋ฉด vector
ย TArray (Unreal)์–ธ๋ฆฌ์–ผํŒ vector. UPROPERTYยทGCยท๋ฆฌํ”Œ๋ ‰์…˜ ํ†ตํ•ฉ
ย TLinkedList / TDoubleLinkedList์–ธ๋ฆฌ์–ผ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ. 1๊ธ‰์ด ์•„๋‹Œ ํ—ฌํผ ์ˆ˜์ค€

๋ชฉ์ฐจ

  1. ํ•ต์‹ฌ ์š”์•ฝ ์นด๋“œ
  2. ๋ฉ”๋ชจ๋ฆฌ ๋ ˆ์ด์•„์›ƒ ์ฐจ์ด
  3. ์‹œ๊ฐ„ ๋ณต์žก๋„ ํ•จ์ • โ€” ์ด๋ก  vs ์‹ค์ธก
  4. CPU ์บ์‹œ โ€” ์‹ค์ œ ์„ฑ๋Šฅ์„ ๊ฒฐ์ •ํ•˜๋Š” ์˜์—ญ โ˜…
  5. iterator ๋ฌดํšจํ™” / ์˜ˆ์™ธ ์•ˆ์ „์„ฑ / ๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ
  6. ์–ธ์ œ list๋ฅผ ์จ์•ผ ํ•˜๋‚˜ โ€” ์‚ฌ์‹ค์ƒ ๊ฑฐ์˜ ์—†์Œ
  7. ์–ธ๋ฆฌ์–ผ TArray vs STL
  8. ํšŒ๊ท€ ๋‹ค๋ฆฌ โ€” ๋‹ค๋ฅธ CS ํŒŒ์ผ ์—ฐ๊ฒฐ
  9. ๊ผฌ๋ฆฌ์งˆ๋ฌธ ์˜ˆ์ƒ ๊ฒฝ๋กœ
  10. ๋ชจ์˜๋ฉด์ ‘ ๋‹ต๋ณ€ ํ…œํ”Œ๋ฆฟ (1๋ถ„ / 3๋ถ„)

1. ํ•ต์‹ฌ ์š”์•ฝ ์นด๋“œ

ํ•œ ์ค„ ์š”์•ฝ 30์ดˆ

1
2
3
4
vector โ€” ์—ฐ์† ๋ฉ”๋ชจ๋ฆฌ. ์บ์‹œ ์นœํ™”. ์ž„์˜ ์ ‘๊ทผ O(1). ๋ push amortized O(1).
list   โ€” ๋…ธ๋“œ ๋ถ„์‚ฐ ํž™. ์บ์‹œ ์ ๋Œ€. ์ž„์˜ ์ ‘๊ทผ O(n). ์ค‘๊ฐ„ ์‚ฝ์ž… ์ด๋ก ์ƒ O(1).
์‹ค์ธก    โ€” ๊ฑฐ์˜ ๋ชจ๋“  ์›Œํฌ๋กœ๋“œ์—์„œ vector ์••์Šน (100๋ฐฐ ์ฐจ์ด๋„ ํ”ํ•จ).
๋ฃฐ     โ€” "์˜์‹ฌ์Šค๋Ÿฌ์šฐ๋ฉด vector. ๊ทธ๋ž˜๋„ ์˜์‹ฌ์Šค๋Ÿฌ์šฐ๋ฉด ๊ทธ๋ž˜๋„ vector."

์‹œ๊ฐ„ ๋ณต์žก๋„ ํ‘œ 30์ดˆ

์—ฐ์‚ฐvectorlist์‹ค์ธก ์šฐ์œ„
์ž„์˜ ์ ‘๊ทผ v[i]O(1)O(n)vector
๋ ์‚ฝ์ž… push_backamortized O(1)O(1)vector (์บ์‹œ)
๋ ์‚ญ์ œ pop_backO(1)O(1)vector
์•ž ์‚ฝ์ž… push_frontO(n)O(1)list (ํฐ N์—์„œ)
์ค‘๊ฐ„ ์‚ฝ์ž… (์œ„์น˜ ์•Œ ๋•Œ)O(n)O(1)๊ฑฐ์˜ vector โ˜…
์ค‘๊ฐ„ ์‚ญ์ œ (์œ„์น˜ ์•Œ ๋•Œ)O(n)O(1)๊ฑฐ์˜ vector โ˜…
๊ฒ€์ƒ‰ findO(n)O(n)vector (์บ์‹œ)
์ˆœ์ฐจ ์ˆœํšŒO(n)O(n)vector ~100๋ฐฐ ๋น ๋ฆ„

โ˜… ํ‘œ์‹œ ํ•ญ๋ชฉ์ด ๋ฉด์ ‘ ๋‹จ๊ณจ ํ•จ์ • โ€” โ€œlist๊ฐ€ O(1)์ธ๋ฐ ์™œ vector๊ฐ€ ๋น ๋ฅธ๊ฐ€โ€

CPU ์บ์‹œ 30์ดˆ

1
2
3
4
5
6
7
8
9
10
11
๋ฉ”๋ชจ๋ฆฌ ๊ณ„์ธต (์†๋„ ๊ฒฉ์ฐจ):
  L1 (~1ns, 32KB)   L2 (~3ns, 256KB)   L3 (~12ns, 8MB)   DRAM (~100ns)
                                                         โ†‘ 100๋ฐฐ ๋А๋ฆผ

์บ์‹œ ๋ผ์ธ = 64๋ฐ”์ดํŠธ โ†’ CPU๊ฐ€ ํ•œ ๋ฒˆ์— ๊ฐ€์ ธ์˜ค๋Š” ๋‹จ์œ„
๊ณต๊ฐ„ ์ง€์—ญ์„ฑ   : ๊ฐ™์€ ๋ผ์ธ์˜ ๋‹ค๋ฅธ ๋ฐ์ดํ„ฐ๋„ ๊ฑฐ์˜ ๊ณต์งœ
์‹œ๊ฐ„ ์ง€์—ญ์„ฑ   : ์ตœ๊ทผ ์“ด ๋ฐ์ดํ„ฐ๋Š” ์บ์‹œ์— ๋‚จ์•„์žˆ์Œ
ํ”„๋ฆฌํŽ˜์ฒ˜     : ์ˆœ์ฐจ ํŒจํ„ด ๊ฐ์ง€ โ†’ ๋‹ค์Œ ๋ผ์ธ ๋ฏธ๋ฆฌ ๋กœ๋“œ

vector:  ์—ฐ์† โ†’ ํ•œ ๋ผ์ธ์— 16๊ฐœ int โ†’ ์บ์‹œ ํžˆํŠธ์œจ โ†‘ โ†’ prefetch ์ž‘๋™
list:    ๋ถ„์‚ฐ โ†’ ๋…ธ๋“œ๋งˆ๋‹ค ์บ์‹œ ๋ฏธ์Šค โ†’ DRAM 100ns ์™•๋ณต N๋ฒˆ โ†’ 100๋ฐฐ ๋А๋ฆผ

๊ผฌ๋ฆฌ์งˆ๋ฌธ ์—ฐ๊ฒฐ ๋งต

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
std::vector vs std::list
โ”œโ”€โ”€ ๋ฉ”๋ชจ๋ฆฌ ๋ ˆ์ด์•„์›ƒ
โ”‚   โ”œโ”€โ”€ ์—ฐ์† ๋ฉ”๋ชจ๋ฆฌ vs ๋ถ„์‚ฐ ๋…ธ๋“œ
โ”‚   โ””โ”€โ”€ capacity / ์„ฑ์žฅ ์ธ์ž (1.5x ~ 2x)
โ”œโ”€โ”€ ์‹œ๊ฐ„ ๋ณต์žก๋„ ํ•จ์ •
โ”‚   โ”œโ”€โ”€ list O(1) ์‚ฝ์ž…์˜ ์‹ค์ฒด โ€” "์œ„์น˜ iterator๋ฅผ ์ด๋ฏธ ๋“ค๊ณ  ์žˆ์„ ๋•Œ"
โ”‚   โ””โ”€โ”€ ๊ฒ€์ƒ‰์ด ํ•„์š”ํ•˜๋ฉด ๊ฒฐ๊ตญ O(n) โ†’ vector๊ฐ€ ์บ์‹œ๋กœ ์••์Šน
โ”œโ”€โ”€ CPU ์บ์‹œ โ˜… (โ˜… ํ•ต์‹ฌ ์˜์—ญ)
โ”‚   โ”œโ”€โ”€ ๋ฉ”๋ชจ๋ฆฌ ๊ณ„์ธต / ์บ์‹œ ๋ผ์ธ 64B
โ”‚   โ”œโ”€โ”€ ๊ณต๊ฐ„ ์ง€์—ญ์„ฑ / ํ”„๋ฆฌํŽ˜์ฒ˜
โ”‚   โ””โ”€โ”€ Stroustrup ๊ฐ•์—ฐ: 1M ์ˆœํšŒ vector ~1ms, list ~100ms
โ”œโ”€โ”€ iterator ๋ฌดํšจํ™”
โ”‚   โ”œโ”€โ”€ vector โ€” ์žฌํ• ๋‹น ์‹œ ์ „์ฒด / insertยทerase ์‹œ ๋ถ€๋ถ„
โ”‚   โ””โ”€โ”€ list โ€” ์‚ญ์ œ ๋…ธ๋“œ ์ž์‹ ๋งŒ (splice/merge ์•ˆ์ „)
โ”œโ”€โ”€ ์˜ˆ์™ธ ์•ˆ์ „์„ฑ
โ”‚   โ”œโ”€โ”€ vector โ€” strong guarantee ์–ด๋ ค์›€ (move ์‹œ noexcept ํ•„์š”)
โ”‚   โ””โ”€โ”€ list โ€” push_back/push_front strong guarantee
โ”œโ”€โ”€ ์–ธ์ œ list?
โ”‚   โ”œโ”€โ”€ ๋งค์šฐ ํฐ ๊ฐ์ฒด + ์žฆ์€ splice + iterator ์•ˆ์ •์„ฑ ํ•„์ˆ˜
โ”‚   โ””โ”€โ”€ ๊ทธ ์™ธ์—” ๊ฑฐ์˜ ํ•ญ์ƒ vector / deque
โ””โ”€โ”€ ์–ธ๋ฆฌ์–ผ TArray
    โ”œโ”€โ”€ vector ๋Œ€์‘ 1๊ธ‰ ์‹œ๋ฏผ
    โ”œโ”€โ”€ ํ‘œ์ค€ list ๋Œ€์‘ ์˜๋„์ ์œผ๋กœ ๋‘์ง€ ์•Š์Œ
    โ””โ”€โ”€ TLinkedList๋Š” ํ—ฌํผ ์ˆ˜์ค€

2. ๋ฉ”๋ชจ๋ฆฌ ๋ ˆ์ด์•„์›ƒ ์ฐจ์ด

ํ•ต์‹ฌ ํ•œ ๋ฌธ์žฅ

vector๋Š” ์—ฐ์† ๋ฉ”๋ชจ๋ฆฌ์— ์›์†Œ๋ฅผ ํ•œ ์ค„๋กœ ๋ฐฐ์น˜ํ•˜๊ณ , list๋Š” ๊ฐ ๋…ธ๋“œ๋ฅผ ํž™ ์—ฌ๊ธฐ์ €๊ธฐ ๋”ฐ๋กœ ํ• ๋‹นํ•ด ํฌ์ธํ„ฐ๋กœ ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค. ์ด ํ•œ ๊ฐ€์ง€ ์ฐจ์ด๊ฐ€ ๋ชจ๋“  ์„ฑ๋Šฅ ํŠน์„ฑ์„ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค.

2-1. vector โ€” ์—ฐ์† ๋ฉ”๋ชจ๋ฆฌ

1
2
3
4
5
6
std::vector<int> v;
v.reserve(8);
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
1
2
3
4
5
6
7
8
9
10
11
ํž™์— ํ•œ ๋ฉ์–ด๋ฆฌ๋กœ ํ• ๋‹น๋œ ๋ฒ„ํผ:

   [10][20][30][40][ . ][ . ][ . ][ . ]
    โ†‘                                โ†‘
    begin()                          capacity ๋ (size=4, capacity=8)

vector ๊ฐ์ฒด ์ž์ฒด๋Š” ๋ณดํ†ต 3๊ฐœ ํฌ์ธํ„ฐ(24๋ฐ”์ดํŠธ, x86_64):
  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  โ”‚ data ptr   โ”‚ size       โ”‚ capacity   โ”‚
  โ””โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
        โ””โ”€โ”€โ†’ ์œ„ ์—ฐ์† ๋ฒ„ํผ์˜ ์ฒซ ์›์†Œ

ํŠน์ง•:

  • &v[0], &v[1], &v[2] โ€ฆ ๊ฐ€ ์—ฐ์†๋œ ์ฃผ์†Œ
  • ํ•œ ๋ฒˆ์˜ operator new๋กœ ์ „์ฒด ๋ฒ„ํผ ํ• ๋‹น โ†’ ํ• ๋‹น์ž ํ˜ธ์ถœ 1ํšŒ
  • v.data()๋กœ raw pointer๋ฅผ ์–ป์–ด C API์— ๊ทธ๋Œ€๋กœ ๋„˜๊ธธ ์ˆ˜ ์žˆ์Œ
  • ์บ์‹œ ๋ผ์ธ 64B ์•ˆ์— int(4B) 16๊ฐœ๊ฐ€ ๋“ค์–ด์˜ด

2-2. list โ€” ๋ถ„์‚ฐ๋œ ๋…ธ๋“œ

1
std::list<int> l = {10, 20, 30, 40};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
๊ฐ ๋…ธ๋“œ๊ฐ€ ํž™์˜ ๋‹ค๋ฅธ ์œ„์น˜์— ๋”ฐ๋กœ ํ• ๋‹น๋จ:

  ์ฃผ์†Œ 0x1000:                    ์ฃผ์†Œ 0x4F80:                    ์ฃผ์†Œ 0x9210:
  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  โ”‚ prev   โ”‚ next   โ”‚ data   โ”‚    โ”‚ prev   โ”‚ next   โ”‚ data   โ”‚    โ”‚ prev   โ”‚ next   โ”‚ data   โ”‚
  โ”‚ nullptrโ”‚ 0x4F80 โ”‚   10   โ”‚    โ”‚ 0x1000 โ”‚ 0x9210 โ”‚   20   โ”‚    โ”‚ 0x4F80 โ”‚ 0xCC30 โ”‚   30   โ”‚
  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

  list ๊ฐ์ฒด ์ž์ฒด:
  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  โ”‚ head     โ”‚ tail     โ”‚ size     โ”‚
  โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
       โ””โ”€โ”€โ†’ ์ฒซ ๋…ธ๋“œ (0x1000)

  ๊ฐ ๋…ธ๋“œ ํฌ๊ธฐ (int ๋ฐ์ดํ„ฐ ๊ธฐ์ค€):
    prev 8B + next 8B + data 4B + ํŒจ๋”ฉ 4B + ํž™ ํ• ๋‹น ํ—ค๋” ~16B
    = 40๋ฐ”์ดํŠธ (์‹ค์ œ ๋ฐ์ดํ„ฐ 4B๋ฅผ ์œ„ํ•ด 36B ์˜ค๋ฒ„ํ—ค๋“œ โ˜…)

ํŠน์ง•:

  • ๋…ธ๋“œ๋งˆ๋‹ค ๊ฐœ๋ณ„ operator new ํ˜ธ์ถœ โ†’ 1M๊ฐœ list = 100๋งŒ ํšŒ ํ• ๋‹น
  • ๋…ธ๋“œ ์ฃผ์†Œ๊ฐ€ ๋ฌด์ž‘์œ„ โ€” next๋กœ ๋”ฐ๋ผ๊ฐ€์•ผ๋งŒ ๋‹ค์Œ์„ ์ฐพ์Œ
  • ๋ฐ์ดํ„ฐ 4๋ฐ”์ดํŠธ๋ฅผ ์œ„ํ•ด 36๋ฐ”์ดํŠธ ์˜ค๋ฒ„ํ—ค๋“œ (900% ๋ฉ”๋ชจ๋ฆฌ ๋‚ญ๋น„)
  • ๋…ธ๋“œ๋“ค์ด ์บ์‹œ ๋ผ์ธ ๊ฒฝ๊ณ„๋ฅผ ๋„˜๋‚˜๋“ค์–ด ๋งค ๋…ธ๋“œ ์ ‘๊ทผ๋งˆ๋‹ค ์ƒˆ ๋ผ์ธ ๋กœ๋“œ ๊ฐ€๋Šฅ์„ฑ

2-3. ์ •๋Ÿ‰ ๋น„๊ต

int 1,000,000๊ฐœ๋ฅผ ๋‹ด๋Š”๋‹ค๊ณ  ๊ฐ€์ • (x86_64):

ํ•ญ๋ชฉvector<int>list<int>
๋ฐ์ดํ„ฐ ๋ฉ”๋ชจ๋ฆฌ4 MB4 MB
๋ฉ”ํƒ€ ์˜ค๋ฒ„ํ—ค๋“œ24 B (๊ฐ์ฒด) + capacity ์Šฌ๋กฏ ์ผ๋ถ€40 MB (๋…ธ๋“œ ํ—ค๋”+ํฌ์ธํ„ฐ)
์ด ๋ฉ”๋ชจ๋ฆฌ~4 MB~44 MB
ํ• ๋‹น์ž ํ˜ธ์ถœ1ํšŒ (์žฌํ• ๋‹น ์ œ์™ธ)1,000,000ํšŒ
์บ์‹œ ๋ผ์ธ ์ ์œ  (์ˆœํšŒ ์‹œ)~62,500๊ฐœ์ตœ๋Œ€ 1,000,000๊ฐœ

list๋Š” ๋ฐ์ดํ„ฐ์˜ 10๋ฐฐ ๋ฉ”๋ชจ๋ฆฌ, 100๋งŒ ๋ฐฐ ํ• ๋‹น ํšŸ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

2-4. capacity์™€ ์„ฑ์žฅ ์ธ์ž

vector๋Š” capacity๊ฐ€ ์ฐจ๋ฉด ๋” ํฐ ๋ฒ„ํผ๋ฅผ ์ƒˆ๋กœ ํ• ๋‹นํ•˜๊ณ  ๊ธฐ์กด ์›์†Œ๋ฅผ ์˜ฎ๊น๋‹ˆ๋‹ค.

1
2
3
4
5
std::vector<int> v;
for (int i = 0; i < 10; ++i) {
    v.push_back(i);
    std::cout << "size=" << v.size() << " cap=" << v.capacity() << "\n";
}
1
2
3
4
5
6
7
8
9
10
size=1  cap=1
size=2  cap=2
size=3  cap=4    โ† ์žฌํ• ๋‹น, 1โ†’2โ†’4
size=4  cap=4
size=5  cap=8    โ† ์žฌํ• ๋‹น
size=6  cap=8
size=7  cap=8
size=8  cap=8
size=9  cap=16   โ† ์žฌํ• ๋‹น
size=10 cap=16

์„ฑ์žฅ ์ธ์ž:

  • libstdc++ (GCC): 2๋ฐฐ ์„ฑ์žฅ โ†’ 1, 2, 4, 8, 16, ...
  • MSVC STL: 1.5๋ฐฐ ์„ฑ์žฅ โ†’ 1, 2, 3, 4, 6, 9, 13, 19, 28, ...
  • 1.5๋ฐฐ๋Š” ๋ฉ”๋ชจ๋ฆฌ ์žฌ์‚ฌ์šฉ์— ์•ฝ๊ฐ„ ์œ ๋ฆฌ, 2๋ฐฐ๋Š” amortized ๋ถ„์„์— ๋‹จ์ˆœ ์œ ๋ฆฌ

amortized O(1)์ด ๋ณด์žฅ๋˜๋Š” ์ด์œ : N๊ฐœ push_back์— ๋ˆ„์  ๋น„์šฉ์ด O(2N) (๋˜๋Š” O(3N))์ด๋ผ ํ‰๊ท ์ด ์ƒ์ˆ˜ ์‹œ๊ฐ„.

1
2
3
4
5
// ๋ฏธ๋ฆฌ reserve๋กœ ์žฌํ• ๋‹น ํšŒํ”ผ โ€” ํฐ ๋ฐ์ดํ„ฐ์— ๋งค์šฐ ํšจ๊ณผ์ 
std::vector<int> v;
v.reserve(1'000'000);          // ํ•œ ๋ฒˆ์— 4MB ํ• ๋‹น
for (int i = 0; i < 1'000'000; ++i)
    v.push_back(i);            // ์žฌํ• ๋‹น ์—†์Œ, ๊ฐ€์žฅ ๋น ๋ฅธ ํŒจํ„ด

3. ์‹œ๊ฐ„ ๋ณต์žก๋„ ํ•จ์ • โ€” ์ด๋ก  vs ์‹ค์ธก

ํ•ต์‹ฌ ํ•œ ๋ฌธ์žฅ

์ด๋ก  ์‹œ๊ฐ„ ๋ณต์žก๋„๋Š” ๊ฐ™์ง€๋งŒ ์‹ค์ธก์€ 100๋ฐฐ ์ฐจ์ด๊ฐ€ ํ”ํ•ฉ๋‹ˆ๋‹ค. โ€œlist๋Š” ์ค‘๊ฐ„ ์‚ฝ์ž…์ด O(1)์ด๋ผ ๋น ๋ฅด๋‹คโ€๋Š” ๊ฐ€์žฅ ์œ ๋ช…ํ•œ ๋ฉด์ ‘ ํ•จ์ •์ž…๋‹ˆ๋‹ค.

3-1. ํ‘œ โ€” ์ด๋ก  ๋ณต์žก๋„

์—ฐ์‚ฐvectorlist์‹ค์ œ ์šฐ์œ„
v[i] ์ž„์˜ ์ ‘๊ทผO(1)O(n)vector โ˜…
front() / back()O(1)O(1)๋™๋ฅ 
push_backamortized O(1)O(1)vector (์บ์‹œ)
pop_backO(1)O(1)vector
push_frontO(n)O(1)list (ํฐ N์—์„œ)
insert(pos, x) (pos ์•Œ๊ณ  ์žˆ์Œ)O(n)O(1)๊ฑฐ์˜ vector โ˜…โ˜…โ˜…
erase(pos) (pos ์•Œ๊ณ  ์žˆ์Œ)O(n)O(1)๊ฑฐ์˜ vector โ˜…โ˜…โ˜…
find(value)O(n)O(n)vector (์บ์‹œ)
์ˆœ์ฐจ ์ˆœํšŒO(n)O(n)vector ~100๋ฐฐ โ˜…โ˜…โ˜…
์ •๋ ฌ sortO(n log n)O(n log n)vector (์บ์‹œ)

3-2. ํ•จ์ • 1 โ€” โ€œlist O(1) ์‚ฝ์ž…โ€์˜ ์‹ค์ฒด

list์˜ O(1) ์‚ฝ์ž…์ด ์œ„์น˜ iterator๋ฅผ ์ด๋ฏธ ์†์— ๋“ค๊ณ  ์žˆ์„ ๋•Œ๋งŒ ์„ฑ๋ฆฝํ•œ๋‹ค๋Š” ์ ์ด ํ•จ์ •์ž…๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
8
9
10
std::list<int> l = { /* 1,000,000 elements */ };

// ์‹œ๋‚˜๋ฆฌ์˜ค A: ์œ„์น˜ iterator๋ฅผ ์ด๋ฏธ ์•Œ๊ณ  ์žˆ์Œ โ€” ์ •์งํ•˜๊ฒŒ O(1)
auto it = SomePreviouslyStoredIterator;
l.insert(it, 999);   // โœ… ์ง„์งœ O(1)

// ์‹œ๋‚˜๋ฆฌ์˜ค B: ๊ฐ’์„ ์ฐพ์•„์„œ ๊ทธ ์•ž์— ์‚ฝ์ž… โ€” find๊ฐ€ O(n)
auto it = std::find(l.begin(), l.end(), targetValue);   // O(n) โ€” ์บ์‹œ ๋ฏธ์Šค ํญํƒ„
l.insert(it, 999);   // O(1)์ด์ง€๋งŒ ์•ž์—์„œ ์ด๋ฏธ O(n)์„ ์ผ์Œ
// ์ด ๋น„์šฉ O(n) + ์บ์‹œ ๋ฏธ์Šค NํšŒ โ‰ซ vector์˜ O(n) ๋ฉ”๋ชจ๋ฆฌ ์ด๋™

ํ˜„์‹ค์ ์ธ ์›Œํฌ๋กœ๋“œ๋Š” ๊ฑฐ์˜ ์‹œ๋‚˜๋ฆฌ์˜ค B์ž…๋‹ˆ๋‹ค. โ€œ๊ฐ’ X ์•ž์— Y๋ฅผ ์‚ฝ์ž…โ€ ๊ฐ™์€ ์š”๊ตฌ์‚ฌํ•ญ์ด ๋Œ€๋ถ€๋ถ„์ด๋ผ, list์˜ O(1)์€ ๊ฑฐ์˜ ํ™œ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

3-3. ํ•จ์ • 2 โ€” vector ์ค‘๊ฐ„ ์‚ฝ์ž…์˜ ์‹ค์ฒด

vector ์ค‘๊ฐ„ ์‚ฝ์ž…์€ ์ด๋ก ์ƒ O(n) (๋’ค์ชฝ ์›์†Œ๋ฅผ ํ•œ ์นธ์”ฉ ๋ฐ€์–ด์•ผ ํ•จ)์ด์ง€๋งŒ:

  • memmove๊ฐ€ SIMD ๋ช…๋ น์–ด๋กœ ํ•œ ๋ฒˆ์— 16~64๋ฐ”์ดํŠธ์”ฉ ์ด๋™
  • ๋ฐ์ดํ„ฐ๊ฐ€ ์ด๋ฏธ ์บ์‹œ์— ์˜ฌ๋ผ์™€ ์žˆ์–ด ๋ฉ”๋ชจ๋ฆฌ ์ ‘๊ทผ์ด ๊ฑฐ์˜ ๋ฌด๋ฃŒ
  • ๋ถ„๊ธฐ ์˜ˆ์ธก์ด ๊ฑฐ์˜ ์™„๋ฒฝ โ€” ํŒŒ์ดํ”„๋ผ์ธ ์ „๋ถ€ ์‚ฌ์šฉ

list ์ค‘๊ฐ„ ์‚ฝ์ž…์€ ์ด๋ก ์ƒ O(1) (ํฌ์ธํ„ฐ ๋‘ ๊ฐœ๋งŒ ๊ฐฑ์‹ )์ด์ง€๋งŒ:

  • ์ƒˆ ๋…ธ๋“œ ํ• ๋‹น์— operator new ํ˜ธ์ถœ (์ˆ˜์‹ญ ns ~ ์ˆ˜๋ฐฑ ns)
  • ํ• ๋‹น์ž๊ฐ€ free list ํƒ์ƒ‰ + lock ๊ฐ€๋Šฅ
  • ์ƒˆ ๋…ธ๋“œ์™€ ์–‘์ชฝ ๋…ธ๋“œ์˜ ์บ์‹œ ๋ฏธ์Šค

๊ฒฐ๊ณผ: N์ด ์ˆ˜๋งŒ~์ˆ˜์‹ญ๋งŒ ์ดํ•˜๋ฉด vector๊ฐ€ ๋” ๋น ๋ฅธ ๊ฒฝ์šฐ๊ฐ€ ์••๋„์ ์œผ๋กœ ๋งŽ์Œ.

3-4. ๋ฒค์น˜๋งˆํฌ ์ธ์‚ฌ์ดํŠธ

Bjarne Stroustrup์˜ ์œ ๋ช…ํ•œ ๊ฐ•์—ฐ (โ€œWhy you should avoid Linked Listsโ€, GoingNative 2012):

โ€œ์ •๋ ฌ๋œ ์ปจํ…Œ์ด๋„ˆ์— N๊ฐœ ์ •์ˆ˜๋ฅผ ๋ฌด์ž‘์œ„ ์œ„์น˜์— ์‚ฝ์ž…ํ•œ๋‹ค. vector์™€ list ์ค‘ ์–ด๋А ๊ฒƒ์ด ๋น ๋ฅผ๊นŒ?โ€

1
2
3
4
5
6
N      | vector  | list
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
   500 |    1ms  |   1ms      โ† ๊ฑฐ์˜ ๋™๋ฅ 
  5000 |    8ms  |  35ms      โ† vector 4๋ฐฐ ๋น ๋ฆ„
 50000 |   85ms  | 1300ms     โ† vector 15๋ฐฐ ๋น ๋ฆ„
500000 | 1100ms  | 35000ms    โ† vector 30๋ฐฐ ๋น ๋ฆ„

๊ฒฐ๋ก (์ง์ ‘ ์ธ์šฉ): โ€œstd::vector๋ฅผ ์“ฐ์„ธ์š”. std::list๋ฅผ ์“ฐ์ง€ ๋งˆ์„ธ์š”. ์˜์‹ฌ์Šค๋Ÿฌ์šฐ๋ฉด ๊ทธ๋ž˜๋„ std::vector๋ฅผ ์“ฐ์„ธ์š”.โ€

์ด ๊ฒฐ๊ณผ๋Š” โ€œlist๋Š” ์บ์‹œ ๋ฏธ์Šค 100ns ร— ๋…ธ๋“œ ์ˆ˜โ€ ๋กœ ์ถ”์ • ๊ฐ€๋Šฅ โ€” ์ธ๋ฑ์‹ฑยท์‚ฝ์ž…์˜ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๋น„์šฉ๋ณด๋‹ค ๋ฉ”๋ชจ๋ฆฌ ์ ‘๊ทผ ๋น„์šฉ์ด ํ›จ์”ฌ ํฝ๋‹ˆ๋‹ค.

3-5. ๊ทธ๋Ÿผ list๊ฐ€ ์ •๋ง ๋น ๋ฅธ ๊ฒฝ์šฐ๋Š”?

์œ„ ๋ฒค์น˜๋งˆํฌ์—์„œ list๊ฐ€ ์ด๊ธด ์ผ€์ด์Šค๋Š” ๊ฑฐ์˜ ์—†์—ˆ์ง€๋งŒ, ์ด๋ก ์ ์œผ๋กœ๋Š”:

1
2
3
4
5
6
// ๋งค์šฐ ํฐ ๊ฐ์ฒด + ์žฆ์€ ์ค‘๊ฐ„ splice
struct HugeNode { char payload[4096]; /* 4KB */ };

std::list<HugeNode> a, b;
// ...
a.splice(a.begin(), b);   // O(1) โ€” ๋…ธ๋“œ ํฌ์ธํ„ฐ๋งŒ ์˜ฎ๊น€. vector๋Š” 4KB ร— N ๋ณต์‚ฌ

์ด ๊ฒฝ์šฐ vector๋Š” ๋ฉ”๋ชจ๋ฆฌ ์ด๋™ ๋น„์šฉ์ด ์ง„์งœ๋กœ ์ปค์ง€๋ฏ€๋กœ list๊ฐ€ ์œ ๋ฆฌ. ๋‹จ ์ด๋Ÿฐ ์›Œํฌ๋กœ๋“œ๋Š” ํ”์น˜ ์•Š์Šต๋‹ˆ๋‹ค (๋ณดํ†ต vector<unique_ptr<HugeNode>>๋กœ ์šฐํšŒ).


4. CPU ์บ์‹œ โ€” ์‹ค์ œ ์„ฑ๋Šฅ์„ ๊ฒฐ์ •ํ•˜๋Š” ์˜์—ญ โ˜…

ํ•ต์‹ฌ ํ•œ ๋ฌธ์žฅ

ํ˜„๋Œ€ CPU๋Š” ๋ฉ”๋ชจ๋ฆฌ๋ณด๋‹ค 100๋ฐฐ ๋น ๋ฅด๊ณ , ๊ทธ ๊ฒฉ์ฐจ๋ฅผ ์บ์‹œ๋กœ ๋ฉ”์›๋‹ˆ๋‹ค. ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์‹œ๊ฐ„ ๋ณต์žก๋„๊ฐ€ ์•„๋‹ˆ๋ผ ์บ์‹œ ์นœํ™”์„ฑ์ด ์‹ค์ œ ์„ฑ๋Šฅ์„ ๊ฒฐ์ •ํ•˜๋ฉฐ, ์ด๊ฒŒ vector๊ฐ€ list๋ฅผ ์••๋„ํ•˜๋Š” ๊ทผ๋ณธ ์ด์œ ์ž…๋‹ˆ๋‹ค.

4-1. ๋ฉ”๋ชจ๋ฆฌ ๊ณ„์ธต (Memory Hierarchy)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
                                       ์†๋„ ๊ฒฉ์ฐจ
                                       (๋Œ€๋žต)
   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ†  CPU ์ฝ”์–ด
   โ”‚   ๋ ˆ์ง€์Šคํ„ฐ       โ”‚     ~32๊ฐœ ร— 64bit, ~0ns        โ˜… ๊ฐ€์žฅ ๋น ๋ฆ„
   โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
   โ”‚   L1 ์บ์‹œ        โ”‚     ~32 KB, ~1 ns              โ†โ”€โ”€โ”€ ๋ฐ์ดํ„ฐ/๋ช…๋ น์–ด ๋ถ„๋ฆฌ
   โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค                                 ์ฝ”์–ด๋‹น ์ „์šฉ
   โ”‚   L2 ์บ์‹œ        โ”‚     ~256 KB, ~3 ns
   โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค                                 ๋ณดํ†ต ์ฝ”์–ด๋‹น ์ „์šฉ
   โ”‚   L3 ์บ์‹œ        โ”‚     ~8 MB, ~12 ns              โ†โ”€โ”€โ”€ ์ฝ”์–ด ๊ฐ„ ๊ณต์œ 
   โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
   โ”‚   DRAM (๋ฉ”์ธ)    โ”‚     ~16 GB, ~100 ns            โ˜… L1 ๋Œ€๋น„ 100๋ฐฐ ๋А๋ฆผ
   โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
   โ”‚   SSD            โ”‚     ~1 TB, ~100,000 ns         (์บ์‹œ ์˜์—ญ๊ณผ๋Š” ๋ณ„๊ฐœ)
   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

ํ•ต์‹ฌ ํ•จ์˜:

  • L1 1ns vs DRAM 100ns โ€” ์บ์‹œ ๋ฏธ์Šค ํ•œ ๋ฒˆ์ด ์•ฝ 100 ์‚ฌ์ดํด ๋‚ญ๋น„
  • ํ˜„๋Œ€ CPU๋Š” ์‚ฌ์ดํด๋‹น 4 ๋ช…๋ น์–ด ์‹คํ–‰ ๊ฐ€๋Šฅ โ†’ ์บ์‹œ ๋ฏธ์Šค 1ํšŒ = ๋ช…๋ น์–ด 400๊ฐœ ๋ถ„๋Ÿ‰์˜ ์‹œ๊ฐ„ ๋‚ญ๋น„
  • ๋”ฐ๋ผ์„œ โ€œ์ฝ”๋“œ๋ฅผ ๋น ๋ฅด๊ฒŒ ํ•˜๋ ค๋ฉด ๋ช…๋ น์–ด ๊ฐœ์ˆ˜๋ณด๋‹ค ๋ฉ”๋ชจ๋ฆฌ ์ ‘๊ทผ ํŒจํ„ด์„ ์ค„์—ฌ๋ผโ€

4-2. ์บ์‹œ ๋ผ์ธ (Cache Line)

CPU๋Š” ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ•œ ๋ฐ”์ดํŠธ์”ฉ ๊ฐ€์ ธ์˜ค์ง€ ์•Š๊ณ  ๋ผ์ธ ๋‹จ์œ„๋กœ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. x86_64์—์„œ ๋ผ์ธ์€ 64๋ฐ”์ดํŠธ.

1
2
3
4
5
6
7
8
9
DRAM์—์„œ L1์œผ๋กœ ํ•œ ๋ฒˆ์— 64๋ฐ”์ดํŠธ ์ „์†ก:

  ์ฃผ์†Œ 0x1000  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
              โ”‚ 64๋ฐ”์ดํŠธ = int 16๊ฐœ / int64 8๊ฐœ / ... โ”‚
  ์ฃผ์†Œ 0x103F  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                 โ†‘ ํ•œ ๋ฒˆ ๊ฐ€์ ธ์˜ค๋ฉด ์ด ์•ˆ์˜ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๊ฐ€ ์บ์‹œ ํžˆํŠธ

  โ–ท vector<int>์˜ 16๊ฐœ ์›์†Œ๊ฐ€ ํ•œ ๋ผ์ธ์— ๋“ค์–ด์˜ด โ†’ ์ฒซ ์ ‘๊ทผ๋งŒ 100ns,
    ๋‚˜๋จธ์ง€ 15๊ฐœ๋Š” ์บ์‹œ ํžˆํŠธ ~1ns

vector ์ˆœํšŒ ๋ถ„์„:

1
2
3
std::vector<int> v(1'000'000);
long sum = 0;
for (int x : v) sum += x;
1
2
3
4
5
6
7
์ฒ˜์Œ ์ ‘๊ทผ:    ์บ์‹œ ๋ฏธ์Šค โ†’ DRAM์—์„œ 64B ๊ฐ€์ ธ์˜ด (16๊ฐœ int) โ€” 100ns
๋‹ค์Œ 15๊ฐœ:    ์บ์‹œ ํžˆํŠธ โ€” 1ns ร— 15 = 15ns
              + ํ”„๋ฆฌํŽ˜์ฒ˜๊ฐ€ ๋‹ค์Œ ๋ผ์ธ์„ ๋ฏธ๋ฆฌ ๊ฐ€์ ธ์˜ด (์‹ค์ œ๋กœ 0ns)
๋‹ค์Œ ๋ฏธ์Šค:    ํ”„๋ฆฌํŽ˜์ฒ˜ ๋•๋ถ„์— ๊ฑฐ์˜ ์•ˆ ์ผ์–ด๋‚จ โ˜…

ํ‰๊ท  ๋น„์šฉ:    ~6 ns/์›์†Œ ๋˜๋Š” ๊ทธ ์ดํ•˜
1M ์ˆœํšŒ:      ~1 ms

4-3. ๊ณต๊ฐ„ ์ง€์—ญ์„ฑ (Spatial Locality)

โ€œ๋ฐฉ๊ธˆ ์ ‘๊ทผํ•œ ์ฃผ์†Œ ๊ทผ์ฒ˜์˜ ๋ฐ์ดํ„ฐ๋„ ๊ณง ์‚ฌ์šฉ๋  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’๋‹คโ€

CPU ์บ์‹œ ์„ค๊ณ„์˜ ๊ฐ€์žฅ ๊ฐ•๋ ฅํ•œ ๊ฐ€์ •. vector๋Š” ์ด ๊ฐ€์ •์„ ์™„๋ฒฝํžˆ ๋งŒ์กฑ์‹œํ‚ต๋‹ˆ๋‹ค.

1
2
3
for (int i = 0; i < 1000000; ++i)
    sum += v[i];          // i, i+1, i+2 ... ๊ฐ€ ์—ฐ์† ์ฃผ์†Œ
                          // โ†’ ํ•œ ๋ผ์ธ์— 16๊ฐœ์”ฉ ๋“ค์–ด์™€ ์ฒ˜๋ฆฌ๋จ

list๋Š” ์ •๋ฐ˜๋Œ€์ž…๋‹ˆ๋‹ค:

1
2
3
for (auto& x : list)      // ๋…ธ๋“œ ์ฃผ์†Œ๊ฐ€ ๋ฌด์ž‘์œ„
    sum += x;             // ๊ฐ ๋…ธ๋“œ๋งˆ๋‹ค ์ƒˆ ๋ผ์ธ ๋กœ๋“œ
                          // โ†’ 1M ๋…ธ๋“œ = 1M ์บ์‹œ ๋ฏธ์Šค ๊ฐ€๋Šฅ์„ฑ

list ์ˆœํšŒ ๋ถ„์„:

1
2
3
4
๊ฐ ๋…ธ๋“œ ์ ‘๊ทผ:  ์บ์‹œ ๋ฏธ์Šค ๊ฐ€๋Šฅ์„ฑ ๋งค์šฐ ๋†’์Œ (๋…ธ๋“œ๊ฐ€ ๋ถ„์‚ฐ๋จ)
              โ†’ 100ns ร— 1M = 100ms โ˜…

์ดํ•ฉ:         ~100 ms (vector ๋Œ€๋น„ ~100๋ฐฐ)

4-4. ์‹œ๊ฐ„ ์ง€์—ญ์„ฑ (Temporal Locality)

โ€œ๋ฐฉ๊ธˆ ์‚ฌ์šฉํ•œ ๋ฐ์ดํ„ฐ๋Š” ๊ณง ๋‹ค์‹œ ์‚ฌ์šฉ๋  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’๋‹คโ€

์บ์‹œ๋Š” LRU ๋น„์Šทํ•œ ์ •์ฑ…์œผ๋กœ ์ตœ๊ทผ ์‚ฌ์šฉ ๋ฐ์ดํ„ฐ๋ฅผ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค. ์ด์ค‘ ๋ฃจํ”„๋‚˜ ์ž‘์€ ๋ฐ์ดํ„ฐ ๋ฐ˜๋ณต ์‚ฌ์šฉ์— ํšจ๊ณผ์ .

1
2
3
4
// ์‹œ๊ฐ„ ์ง€์—ญ์„ฑ์ด ์ข‹์€ ์ฝ”๋“œ
for (int iter = 0; iter < 100; ++iter)
    for (int i = 0; i < 1000; ++i)   // ๊ฐ™์€ 1000๊ฐœ ๋ฐ์ดํ„ฐ ๋ฐ˜๋ณต โ†’ L1์— ์ƒ์ฃผ
        v[i] = process(v[i]);

4-5. ํ•˜๋“œ์›จ์–ด ํ”„๋ฆฌํŽ˜์ฒ˜ (Hardware Prefetcher)

CPU์—๋Š” โ€œ๋ฉ”๋ชจ๋ฆฌ ์ ‘๊ทผ ํŒจํ„ด์„ ๊ฐ์ง€ํ•ด ๋‹ค์Œ ๋ผ์ธ์„ ๋ฏธ๋ฆฌ ๊ฐ€์ ธ์˜ค๋Š” ํšŒ๋กœโ€œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
์ˆœ์ฐจ ํŒจํ„ด ๊ฐ์ง€ ์‹œ:
  CPU๊ฐ€ ๋ผ์ธ N์„ ์ฝ์œผ๋ฉด  โ†’ ํšŒ๋กœ๊ฐ€ N+1์„ ๋ฏธ๋ฆฌ ์š”์ฒญ
  CPU๊ฐ€ ๋ผ์ธ N+1์„ ์ฝ์œผ๋ฉด โ†’ ํšŒ๋กœ๊ฐ€ N+2๋ฅผ ์ด๋ฏธ ๊ฐ€์ ธ์˜จ ์ƒํƒœ
  โ†’ ๋ฉ”๋ชจ๋ฆฌ ์ง€์—ฐ์ด ์‚ฌ์‹ค์ƒ ์‚ฌ๋ผ์ง โ˜…

์ŠคํŠธ๋ผ์ด๋“œ ํŒจํ„ด ๊ฐ์ง€ ์‹œ:
  v[0], v[16], v[32], ... โ†’ ์ผ์ • ๊ฐ„๊ฒฉ ๊ฐ์ง€ โ†’ ๋ฏธ๋ฆฌ ๋กœ๋“œ

๋ฌด์ž‘์œ„ ์ ‘๊ทผ:
  list ๋…ธ๋“œ next ํฌ์ธํ„ฐ ๋”ฐ๋ผ๊ฐ€๊ธฐ โ†’ ํŒจํ„ด ์—†์Œ โ†’ ํ”„๋ฆฌํŽ˜์ฒ˜ ๋ฌด๋ ฅ
  โ†’ DRAM 100ns ร— N๋ฒˆ ๊ทธ๋Œ€๋กœ ๋ถ€๋‹ด

vector๊ฐ€ ๋น ๋ฅธ ์ด์œ ์˜ ์ ˆ๋ฐ˜์€ ํ”„๋ฆฌํŽ˜์ฒ˜ ๋•๋ถ„์ด๋ผ ํ•ด๋„ ๊ณผ์žฅ์ด ์•„๋‹™๋‹ˆ๋‹ค.

4-6. ์‹œ๊ฐํ™” โ€” ์บ์‹œ ๋ผ์ธ ์ ์œ  ์ฐจ์ด

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
vector<int>๊ฐ€ ์บ์‹œ ๋ผ์ธ์„ ์ฑ„์šฐ๋Š” ๋ชจ์Šต:

  L1 ์บ์‹œ ๋ผ์ธ (64B):
  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  โ”‚ v[0] v[1] v[2] v[3] v[4] v[5] ... v[15]                 โ”‚
  โ”‚ 4B   4B   4B   4B   4B   4B       4B                    โ”‚  โ† 16๊ฐœ ์ •์ˆ˜๊ฐ€ ํ•œ ๋ผ์ธ์—
  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  โ–ฒ 1๋ฒˆ ๋ฏธ์Šค๋กœ 16๊ฐœ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ

list<int> ๋…ธ๋“œ๊ฐ€ ์บ์‹œ ๋ผ์ธ์„ ์ฐจ์ง€ํ•˜๋Š” ๋ชจ์Šต:

  L1 ์บ์‹œ ๋ผ์ธ #1 (๋…ธ๋“œ A ์œ„์น˜):
  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  โ”‚ A.prev A.next A.data โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’ (๋‹ค๋ฅธ ํž™ ๋ฐ์ดํ„ฐ) โ–’โ–’โ–’โ–’โ–’โ–’โ”‚
  โ”‚  8B    8B    4B      โ† 20B ์‚ฌ์šฉ                           โ”‚
  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

  L1 ์บ์‹œ ๋ผ์ธ #2 (์–ด๋”˜๊ฐ€ ๋ฉ€๋ฆฌ, ๋…ธ๋“œ B ์œ„์น˜):
  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  โ”‚ โ–’โ–’โ–’โ–’โ–’โ–’ B.prev B.next B.data โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ”‚
  โ”‚         8B    8B    4B                                   โ”‚
  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  โ–ฒ ๋งค ๋…ธ๋“œ๋งˆ๋‹ค 1๋ฒˆ ๋ฏธ์Šค โ†’ 16๋ฐฐ ๋” ๋งŽ์€ ๋ฏธ์Šค
  โ–ฒ ๋ฐ์ดํ„ฐ 4B๋ฅผ ์œ„ํ•ด 64B ๋ผ์ธ ํ•œ ์ค„์„ ํ†ต์งธ๋กœ ๊ฐ€์ ธ์˜ค๋Š” ์…ˆ โ†’ ์บ์‹œ ํšจ์œจ ~6%

4-7. ๋ฒค์น˜๋งˆํฌ ์žฌํ•ด์„

3์žฅ์—์„œ ๋ณธ Stroustrup ๋ฒค์น˜๋งˆํฌ์˜ 100๋ฐฐ ์ฐจ์ด๋ฅผ ์บ์‹œ๋กœ ๋ถ„์„ํ•˜๋ฉด:

1
2
3
4
5
6
vector  1M ์ˆœํšŒ: ์บ์‹œ ๋ฏธ์Šค ~62,500ํšŒ (1M / 16) ร— 100ns = ~6.25 ms
                + ํ”„๋ฆฌํŽ˜์ฒ˜๋กœ ์ ˆ๋ฐ˜ ์ด์ƒ ํก์ˆ˜ โ†’ ~1 ms ์‹ค์ธก
list    1M ์ˆœํšŒ: ์บ์‹œ ๋ฏธ์Šค ~1,000,000ํšŒ ร— 100ns = ~100 ms ์‹ค์ธก
                โ†‘ ๊ฑฐ์˜ ๊ทธ๋Œ€๋กœ ๋ถ€๋‹ด

๋ฐฐ์ˆ˜    : ~100๋ฐฐ โ€” ์ธก์ •๊ฐ’๊ณผ ์ผ์น˜

์ด๊ฒŒ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๋ณต์žก๋„ ๋ถ„์„์œผ๋กœ๋Š” ์ ˆ๋Œ€ ์•ˆ ๋ณด์ด๋Š” 100๋ฐฐ ๊ฒฉ์ฐจ์˜ ์ •์ฒด์ž…๋‹ˆ๋‹ค.

4-8. ์‹ค์ „ ๊ด€์šฉ๊ตฌ โ€” โ€œ์บ์‹œ ์นœํ™” ์šฐ์„ โ€

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Bad โ€” list๋กœ ์ž์ฃผ ์ˆœํšŒ
std::list<Entity> entities;
for (auto& e : entities) e.update();   // ์บ์‹œ ๋ฏธ์Šค ํญํƒ„

// Good โ€” vector๋กœ ์šฐ์„  ์‹œ๋„
std::vector<Entity> entities;
for (auto& e : entities) e.update();   // SoA๋ฅผ ๋” ์ ์šฉํ•˜๋ฉด ๋” ๋น ๋ฆ„

// Better โ€” Structure of Arrays (SoA) ํŒจํ„ด
struct EntitySystem {
    std::vector<Vec3>   positions;
    std::vector<Vec3>   velocities;
    std::vector<float>  hps;
    // ์œ„์น˜ ์—…๋ฐ์ดํŠธ๋Š” positions/velocities๋งŒ ์ˆœํšŒ โ†’ ๋” ํฐ ์บ์‹œ ํšจ์œจ
};

๊ฒŒ์ž„ ์—”์ง„(Unreal, Unity DOTS, Bevy ๋“ฑ)์ด ECS(Entity Component System)๋กœ SoA๋ฅผ ์ฑ„ํƒํ•˜๋Š” ์ด์œ ์˜ ์ ˆ๋ฐ˜์ด ์ด ์บ์‹œ ์นœํ™”์„ฑ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.


5. iterator ๋ฌดํšจํ™” / ์˜ˆ์™ธ ์•ˆ์ „์„ฑ / ๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ

5-1. iterator ๋ฌดํšจํ™” ๊ทœ์น™

vector

์—ฐ์‚ฐ๋ฌดํšจํ™” ๋ฒ”์œ„
push_back, emplace_back์žฌํ• ๋‹น ์‹œ ๋ชจ๋“  iterator/ํฌ์ธํ„ฐ/์ฐธ์กฐ ๋ฌดํšจ
insert(pos, ...)์žฌํ• ๋‹น ์‹œ ์ „๋ถ€, ์•„๋‹ˆ๋ฉด pos ์ดํ›„ ๋ชจ๋‘
erase(pos)pos ์ดํ›„ ๋ชจ๋‘
clear()๋ชจ๋‘ (end๋„ ํฌํ•จ)
reserve(n) (n > capacity)๋ชจ๋‘
shrink_to_fit()์ž ์žฌ์ ์œผ๋กœ ๋ชจ๋‘
resize์ž ์žฌ์ ์œผ๋กœ ๋ชจ๋‘
1
2
3
4
5
std::vector<int> v = {1, 2, 3};
auto it = v.begin();          // it โ†’ &v[0]

v.push_back(4);               // ์žฌํ• ๋‹น ๋ฐœ์ƒ ๊ฐ€๋Šฅ โ†’ it ๋ฌดํšจํ™” ๊ฐ€๋Šฅ!
std::cout << *it;             // โŒ UB (์šด์ด ์ข‹์•„ ๋™์ž‘ํ•  ์ˆ˜๋„, ํฌ๋ž˜์‹œํ•  ์ˆ˜๋„)

list

์—ฐ์‚ฐ๋ฌดํšจํ™” ๋ฒ”์œ„
push_back/push_front๋ฌดํšจํ™” ์—†์Œ โ˜…
insert(pos, ...)๋ฌดํšจํ™” ์—†์Œ โ˜…
erase(pos)์‚ญ์ œ๋œ ๋…ธ๋“œ๋งŒ โ˜…
splice (๋‹ค๋ฅธ list๋กœ ๋…ธ๋“œ ์ด๋™)๋ฌดํšจํ™” ์—†์Œ (iterator๋Š” ์ƒˆ list์—์„œ ์œ ํšจ)
clear()๋ชจ๋‘
merge, sort์•ˆ์ „ (๋…ธ๋“œ ์ž๋ฆฌ๋งŒ ๋ฐ”๋€œ, iterator ์œ ํšจ)
1
2
3
4
5
6
7
std::list<int> l = {1, 2, 3};
auto it = std::next(l.begin());   // it โ†’ 2

l.push_back(4);                   // โœ… it ๊ทธ๋Œ€๋กœ ์œ ํšจ
l.push_front(0);                  // โœ… it ๊ทธ๋Œ€๋กœ ์œ ํšจ
l.insert(l.begin(), -1);          // โœ… it ๊ทธ๋Œ€๋กœ ์œ ํšจ
*it;                              // โœ… 2 โ€” ์•ˆ์ „

์ด ๋…ธ๋“œ ์•ˆ์ •์„ฑ์ด list์˜ ๊ฑฐ์˜ ์œ ์ผํ•˜๊ฒŒ ์ •์งํ•œ ์ด์ ์ž…๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์ž๋ฃŒ๊ตฌ์กฐ์— iterator/ํฌ์ธํ„ฐ๋ฅผ ์ €์žฅํ•ด ๋‘๊ณ  ์‹ถ์„ ๋•Œ ์œ ์šฉ.

5-2. ์˜ˆ์™ธ ์•ˆ์ „์„ฑ (Exception Safety)

๋ณด์žฅ ๋‹จ๊ณ„ ๋ณต์Šต

๋‹จ๊ณ„์˜๋ฏธ
No-throw์ ˆ๋Œ€ ์˜ˆ์™ธ ๋˜์ง€์ง€ ์•Š์Œ
Strong์˜ˆ์™ธ ๋ฐœ์ƒ ์‹œ ์ƒํƒœ ๋ถˆ๋ณ€ (๋กค๋ฐฑ)
Basic์˜ˆ์™ธ ๋ฐœ์ƒํ•ด๋„ ์ž์› ๋ˆ„์ˆ˜ ์—†์Œ, ์ƒํƒœ๋Š” ์ผ๊ด€์„ฑ ์žˆ์Œ
No guarantee์œ„ ์–ด๋А ๊ฒƒ๋„ ๋ณด์žฅ ์•ˆ ๋จ

vector์˜ ์˜ˆ์™ธ ์•ˆ์ „์„ฑ

1
2
3
std::vector<Widget> v;
v.push_back(w);   // ์žฌํ• ๋‹น ์‹œ ๊ธฐ์กด ์›์†Œ๋“ค์„ ์ƒˆ ๋ฒ„ํผ๋กœ ์˜ฎ๊ฒจ์•ผ ํ•จ
                  // โ†’ ์˜ฎ๊ธฐ๋Š” ๋„์ค‘ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด?
  • Widget์ด noexcept ์ด๋™ ์ƒ์„ฑ์ž๋ฅผ ๊ฐ€์ง€๋ฉด โ†’ vector๋Š” move๋ฅผ ์‚ฌ์šฉํ•ด strong guarantee ์ œ๊ณต
  • Widget์˜ ์ด๋™ ์ƒ์„ฑ์ž๊ฐ€ throw ๊ฐ€๋Šฅํ•˜๋ฉด โ†’ vector๋Š” ์•ˆ์ „์„ ์œ„ํ•ด copy ์‚ฌ์šฉ (๋А๋ฆผ) โ†’ strong guarantee ๊ฐ€๋Šฅ
  • ๋ณต์‚ฌ ์ƒ์„ฑ์ž๋„ throwํ•˜๋ฉด โ†’ basic guarantee๋กœ ๊ฐ•๋“ฑ
1
2
3
4
class Widget {
public:
    Widget(Widget&&) noexcept;   // โ˜… ์ด๊ฒŒ ์žˆ์–ด์•ผ vector๊ฐ€ ๋น ๋ฅธ strong guarantee ์‚ฌ์šฉ
};

list์˜ ์˜ˆ์™ธ ์•ˆ์ „์„ฑ

  • push_back/push_front/insert๋Š” strong guarantee ์ž๋™ (์ƒˆ ๋…ธ๋“œ ํ• ๋‹น๋งŒ ์‹คํŒจํ•˜๋ฉด list๋Š” ๋ณ€๊ฒฝ ์—†์Œ)
  • ๋…ธ๋“œ ๋‹จ์œ„๋ผ ์ด๋™ ๋น„์šฉ๋„ ์—†๊ณ  ๋กค๋ฐฑ๋„ ๋‹จ์ˆœ
  • ์ด๊ฒŒ list์˜ ๋˜ ๋‹ค๋ฅธ ์ •์งํ•œ ์ด์ 

5-3. ๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ

ํ•ญ๋ชฉvectorlist
๋…ธ๋“œ๋‹น ์˜ค๋ฒ„ํ—ค๋“œ0 (capacity ์—ฌ์œ ๋ถ„ ์ผ๋ถ€)prev 8B + next 8B + ํž™ ํ—ค๋” ~16B = 32B+
ํ• ๋‹น์ž ํ˜ธ์ถœ1ํšŒ (๋˜๋Š” reserve๋กœ 0ํšŒ)๋…ธ๋“œ๋‹น 1ํšŒ
๋ฉ”๋ชจ๋ฆฌ ๋‹จํŽธํ™”๊ฑฐ์˜ ์—†์Œ์‹ฌ๊ฐ (์ž‘์€ ๋ธ”๋ก ๋Œ€๋Ÿ‰ ๋ฐœ์ƒ)
๋ฐ์ดํ„ฐ ํšจ์œจ (int ๊ธฐ์ค€)~95%+~10% (4B ๋ฐ์ดํ„ฐ / 40B ๋…ธ๋“œ)
TLB ์••๋ฐ•๋‚ฎ์Œ (์—ฐ์† ํŽ˜์ด์ง€)๋†’์Œ (๋ถ„์‚ฐ ํŽ˜์ด์ง€)

int 1,000,000๊ฐœ:

  • vector: ์•ฝ 4 MB
  • list: ์•ฝ 40 MB

big object์ผ์ˆ˜๋ก ์ฐจ์ด๊ฐ€ ์ค„์ง€๋งŒ, ๋ณดํ†ต 1~3๋ฐฐ ๋ฉ”๋ชจ๋ฆฌ ์ฐจ์ด๋Š” ํ•ญ์ƒ ์žˆ์Šต๋‹ˆ๋‹ค.

5-4. ๋‹ค๋ฅธ ์ฐจ์ด ์ข…ํ•ฉํ‘œ

ย vectorlist
๋ฉ”๋ชจ๋ฆฌ ๋ ˆ์ด์•„์›ƒ์—ฐ์†๋ถ„์‚ฐ ๋…ธ๋“œ
์ž„์˜ ์ ‘๊ทผO(1)O(n)
์ˆœ์ฐจ ์ˆœํšŒ (์‹ค์ธก)๋งค์šฐ ๋น ๋ฆ„๋งค์šฐ ๋А๋ฆผ
๋ push (์‹ค์ธก)๋งค์šฐ ๋น ๋ฆ„๋ณดํ†ต
์ค‘๊ฐ„ ์‚ฝ์ž… (์œ„์น˜ ์•Œ ๋•Œ)O(n), ์บ์‹œ๋กœ ๋น ๋ฆ„O(1), ํ• ๋‹น์œผ๋กœ ๋А๋ฆด ์ˆ˜ ์žˆ์Œ
iterator ์•ˆ์ •์„ฑ์•ฝํ•จ (์žฌํ• ๋‹น ์œ„ํ—˜)๊ฐ•ํ•จ (์‚ญ์ œ ๋…ธ๋“œ๋งŒ ๋ฌดํšจ)
์˜ˆ์™ธ ์•ˆ์ „์„ฑ (push)์กฐ๊ฑด๋ถ€ strong์ž๋™ strong
๋ฉ”๋ชจ๋ฆฌ ์˜ค๋ฒ„ํ—ค๋“œ์ž‘์Œํผ (๋…ธ๋“œ๋‹น 32B+)
์บ์‹œ ์นœํ™”์„ฑโ˜…โ˜…โ˜…โ˜…โ˜…โ˜…
๊ถŒ์žฅ๋„๊ธฐ๋ณธ ์„ ํƒ๊ฑฐ์˜ ์•ˆ ์”€

6. ์–ธ์ œ list๋ฅผ ์จ์•ผ ํ•˜๋‚˜ โ€” ์‚ฌ์‹ค์ƒ ๊ฑฐ์˜ ์—†์Œ

ํ•ต์‹ฌ ํ•œ ๋ฌธ์žฅ

ํ˜„๋Œ€ ํ•˜๋“œ์›จ์–ด์—์„œ std::list๋Š” ๊ฑฐ์˜ ํ•ญ์ƒ ์ž˜๋ชป๋œ ์„ ํƒ์ž…๋‹ˆ๋‹ค. ์ •๋‹นํ™”๋˜๋Š” ์ผ€์ด์Šค๋Š” ๊ทนํžˆ ์ข๊ณ , ๊ทธ๋งˆ์ €๋„ ๋ณดํ†ต ๋‹ค๋ฅธ ์ž๋ฃŒ๊ตฌ์กฐ๋กœ ๋Œ€์ฒด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

6-1. list๊ฐ€ ์ •๋‹นํ™”๋˜๋Š” ๋“œ๋ฌธ ์ผ€์ด์Šค

1
2
3
4
5
6
์กฐ๊ฑด (๋ชจ๋‘ ๋งŒ์กฑํ•ด์•ผ ํ•จ):
  1) ๋งค์šฐ ํฐ ๊ฐ์ฒด (์ˆ˜ KB ์ด์ƒ) โ€” ์ด๋™ ๋น„์šฉ์ด ์ง„์งœ ํฐ ๊ฒฝ์šฐ
  2) ์žฆ์€ splice/merge โ€” ๋…ธ๋“œ ์žฌ๋ฐฐ์น˜๊ฐ€ ์ฃผ ์ž‘์—…
  3) iterator/ํฌ์ธํ„ฐ ์•ˆ์ •์„ฑ์ด ์ ˆ๋Œ€์  ํ•„์ˆ˜ โ€” ์™ธ๋ถ€ ๊ตฌ์กฐ์— ์ €์žฅํ•ด์•ผ ํ•จ
  4) ๊ฒ€์ƒ‰์€ ๊ฑฐ์˜ ์•ˆ ํ•จ โ€” ์œ„์น˜ iterator๋ฅผ ํ•ญ์ƒ ์†์— ๋“ค๊ณ  ์žˆ์Œ
  5) ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์€ ์‹ ๊ฒฝ ์•ˆ ์”€

์ด 5๊ฐ€์ง€๊ฐ€ ๋ชจ๋‘ ์ถฉ์กฑ๋˜๋Š” ๊ฒฝ์šฐ๋Š” ์‹ค๋ฌด์—์„œ ๋งค์šฐ ๋“œ๋ญ…๋‹ˆ๋‹ค. ํ•˜๋‚˜๋ผ๋„ ๋น ์ง€๋ฉด vector(๋˜๋Š” vectorยทdeque)๊ฐ€ ๋” ๋‚ซ์Šต๋‹ˆ๋‹ค.

6-2. ๋” ์ž์ฃผ ์ ํ•ฉํ•œ ๋Œ€์•ˆ โ€” std::deque

vector์™€ list์˜ ์ ˆ์ถฉ์•ˆ์ž…๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
8
9
10
deque ๋ฉ”๋ชจ๋ฆฌ ๋ ˆ์ด์•„์›ƒ:

   chunk 0 (4KB)        chunk 1 (4KB)        chunk 2 (4KB)
  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  โ”‚ [.][.][a][b][c] โ”‚   โ”‚ [d][e][f][g][h] โ”‚   โ”‚ [i][j][k][.][.] โ”‚
  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
       โ†‘                                              โ†‘
     front                                           back

   ์ง์ ‘ ์ธ๋ฑ์‹ฑ ๊ฐ€๋Šฅ (chunk ์ธ๋ฑ์Šค + ์•ˆ์—์„œ ์˜คํ”„์…‹) โ†’ O(1) ์ž„์˜ ์ ‘๊ทผ
ํŠน์„ฑvectordequelist
์ž„์˜ ์ ‘๊ทผO(1) ๋น ๋ฆ„O(1) ์•ฝ๊ฐ„ ๋А๋ฆผO(n)
push_backamortized O(1)O(1) (์žฌํ• ๋‹น ๊ฑฐ์˜ ์—†์Œ)O(1)
push_frontO(n)O(1) โ˜…O(1)
์บ์‹œ ์นœํ™”์ตœ๊ณ ๋ณดํ†ต (์ฒญํฌ ์•ˆ์—์„œ๋งŒ)์ตœ์•…
iterator ์•ˆ์ •์„ฑ์•ฝํ•จ์•ฝํ•จ (front/back push๋งŒ ์•ˆ์ „)๊ฐ•ํ•จ
๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ์ตœ๊ณ ๋ณดํ†ต์ตœ์•…

deque ์ถ”์ฒœ ์ผ€์ด์Šค:

  • push_front์™€ push_back์ด ๋ชจ๋‘ ์ž์ฃผ ํ•„์š” (queue)
  • ํฐ ์ปจํ…Œ์ด๋„ˆ์ธ๋ฐ ์žฌํ• ๋‹น์˜ ์ด๋™ ๋น„์šฉ์ด ๋ถ€๋‹ด๋จ
  • ํ‘œ์ค€ std::queue/std::stack์€ ๊ธฐ๋ณธ ์ปจํ…Œ์ด๋„ˆ๋กœ deque ์‚ฌ์šฉ

6-3. ๋” ๋‚˜์€ ๋Œ€์•ˆ โ€” vector<unique_ptr<T>>

ํฐ ๊ฐ์ฒด + iterator ์•ˆ์ •์„ฑ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ, ์ง„์งœ ๋‹ต์€ ๋ณดํ†ต ์ด ํŒจํ„ด์ž…๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
8
struct HugeNode { char payload[4096]; };

std::vector<std::unique_ptr<HugeNode>> nodes;

// vector ์ž์ฒด๋Š” ํฌ์ธํ„ฐ 8B๋งŒ ์ด๋™ โ†’ ์บ์‹œ ์นœํ™” + ์ด๋™ ๋น ๋ฆ„
// ๊ฐ์ฒด ์ž์ฒด๋Š” ํž™์— ๊ณ ์ • โ†’ ํฌ์ธํ„ฐ/์ฐธ์กฐ ์•ˆ์ •์„ฑ (์žฌํ• ๋‹นํ•ด๋„ *p๋Š” ์œ ํšจ)
HugeNode* p = nodes[42].get();
nodes.push_back(std::make_unique<HugeNode>());   // ์žฌํ• ๋‹น๋ผ๋„ p๋Š” ์œ ํšจ โ˜…

์žฅ์ :

  • ์ปจํ…Œ์ด๋„ˆ ์ˆœํšŒ๋Š” ๋น ๋ฆ„ (ํฌ์ธํ„ฐ๋งŒ ์ˆœํšŒ)
  • ๊ฐ์ฒด๋Š” ํž™์— ๊ณ ์ • โ†’ ์™ธ๋ถ€์—์„œ ์•ˆ์ „ํ•˜๊ฒŒ ์ฐธ์กฐ ๊ฐ€๋Šฅ
  • list์˜ ๋ชจ๋“  ์žฅ์  + vector์˜ ์บ์‹œ ์นœํ™”์„ฑ

11๋ฒˆ [์Šค๋งˆํŠธ ํฌ์ธํ„ฐ] ์™€ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์—ฐ๊ฒฐ๋˜๋Š” ํŒจํ„ด์ž…๋‹ˆ๋‹ค.

6-4. std::forward_list ๋น„๊ต

C++11์—์„œ ์ถ”๊ฐ€๋œ ๋‹จ๋ฐฉํ–ฅ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ.

1
2
3
4
struct ForwardNode {
    ForwardNode* next;   // prev ์—†์Œ โ†’ 8๋ฐ”์ดํŠธ ์ ˆ์•ฝ
    T data;
};
  • ๋…ธ๋“œ๋‹น 8B ์ ˆ์•ฝ (prev ํฌ์ธํ„ฐ ์ œ๊ฑฐ)
  • size() ๋ฉค๋ฒ„ ํ•จ์ˆ˜ ์—†์Œ (์„ฑ๋Šฅ ์œ„ํ•ด)
  • ์ž„๋ฒ ๋””๋“œ/๋ฉ”๋ชจ๋ฆฌ ์ œ์•ฝ ํ™˜๊ฒฝ์—์„œ ๊ฐ€๋” ์ •๋‹นํ™”
  • ์ผ๋ฐ˜ ๋ฐ์Šคํฌํ†ฑยท์„œ๋ฒ„ยท๊ฒŒ์ž„์—์„œ๋Š” ์—ฌ์ „ํžˆ vector๊ฐ€ ์œ ๋ฆฌ

6-5. โ€œVector Firstโ€ ์›์น™

์—…๊ณ„ ๊ถŒ์œ„์ž๋“ค์ด ๊ฑฐ์˜ ๋งŒ์žฅ์ผ์น˜๋กœ ์ถ”์ฒœ:

  • Bjarne Stroustrup (C++ ์ฐฝ์‹œ์ž): โ€œUse vector. Donโ€™t use list unless you have a very specific reason.โ€
  • Herb Sutter (C++ Standards Committee): โ€œIf youโ€™re not sure, use vector.โ€
  • Sean Parent (Adobe principal): โ€œNo raw loops. No raw owners. Default container is vector.โ€

โ€œ์„ฑ๋Šฅ์ด ์˜์‹ฌ์Šค๋Ÿฌ์šด ์ƒํ™ฉ์—์„œ๋Š” ์ธก์ •ํ•˜๊ธฐ ์ „์— vector๋กœ ์‹œ์ž‘ํ•˜๋ผ. list๋กœ ๋ฐ”๊ฟ€ ์ด์œ ๋Š” ์ธก์ •์ด list๊ฐ€ ๋” ๋น ๋ฆ„์„ ์ฆ๋ช…ํ•œ ํ›„์—์•ผ ์ƒ๊ธด๋‹ค.โ€

์ด๊ฒŒ 13๋ฒˆ ์ฃผ์ œ์˜ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ํ•œ ์ค„ ๊ฒฐ๋ก ์ž…๋‹ˆ๋‹ค.


7. ์–ธ๋ฆฌ์–ผ TArray vs STL

ํ•ต์‹ฌ ํ•œ ๋ฌธ์žฅ

์–ธ๋ฆฌ์–ผ์€ TArray๋ฅผ vector ๋Œ€์‘์˜ 1๊ธ‰ ์‹œ๋ฏผ์œผ๋กœ ๋‘๊ณ , std::list ๋Œ€์‘ ์ž๋ฃŒ๊ตฌ์กฐ๋Š” ์˜๋„์ ์œผ๋กœ 1๊ธ‰์œผ๋กœ ๋‘์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ์บ์‹œ ์นœํ™” ์ฒ ํ•™์ด ๊ฒŒ์ž„ ์—”์ง„์—์„œ ๋” ๊ฐ•ํ•˜๊ฒŒ ์ ์šฉ๋ฉ๋‹ˆ๋‹ค.

7-1. TArray<T> โ€” ์–ธ๋ฆฌ์–ผํŒ vector

1
2
3
4
5
6
7
8
9
10
11
TArray<int32> Arr;
Arr.Add(10);                  // std::vector::push_back ๋Œ€์‘
Arr.Insert(20, 0);            // std::vector::insert ๋Œ€์‘
Arr.RemoveAt(0);              // std::vector::erase ๋Œ€์‘
Arr.RemoveAtSwap(0);          // ๋งˆ์ง€๋ง‰ ์›์†Œ์™€ swap ํ›„ pop_back โ€” O(1) ๋น ๋ฅธ ์‚ญ์ œ
int32 V = Arr[0];             // ์ž„์˜ ์ ‘๊ทผ

// Reserve / SetNum
Arr.Reserve(1000);            // std::vector::reserve ๋Œ€์‘
Arr.SetNum(500);              // resize ๋Œ€์‘
Arr.Empty();                  // clear ๋Œ€์‘

๋‚ด๋ถ€ ๊ตฌ์กฐ๋Š” std::vector์™€ ๊ฑฐ์˜ ๋™์ผ:

  • ์—ฐ์† ๋ฉ”๋ชจ๋ฆฌ ๋™์  ๋ฐฐ์—ด
  • ์„ฑ์žฅ ์ธ์ž ๋ณดํ†ต 1.5x ~ 2x (DefaultAllocator)
  • ์บ์‹œ ์นœํ™”

7-2. UPROPERTY ยท GC ํ†ตํ•ฉ

1
2
3
4
5
6
7
UCLASS()
class AMyActor : public AActor {
    GENERATED_BODY()
public:
    UPROPERTY()
    TArray<UItem*> Items;     // GC๊ฐ€ ๋ชจ๋“  ์›์†Œ ์ถ”์ , ๋ฆฌํ”Œ๋ ‰์…˜ ๋…ธ์ถœ
};
  • UPROPERTY()๋กœ ์„ ์–ธํ•˜๋ฉด GC๊ฐ€ ์ปจํ…Œ์ด๋„ˆ ์•ˆ UObject๊นŒ์ง€ ์ž๋™ ์ถ”์ 
  • ๋ธ”๋ฃจํ”„๋ฆฐํŠธ ๋…ธ์ถœ, ๋””ํ…Œ์ผ ํŒจ๋„ ํŽธ์ง‘, replication ์ง€์›
  • std::vector<UItem*>์€ GC๊ฐ€ ์ถ”์  ๋ชป ํ•จ โ†’ ์–ธ๋ฆฌ์–ผ์—์„œ๋Š” ์ ˆ๋Œ€ ์“ฐ์ง€ ์•Š์Œ

7-3. TArray::RemoveAt vs RemoveAtSwap

1
2
3
4
5
6
7
TArray<int32> Arr = {1, 2, 3, 4, 5};

// ์•ˆ์ • ์‚ญ์ œ (์ˆœ์„œ ์œ ์ง€) โ€” std::vector::erase์™€ ๋™์ผ, O(n)
Arr.RemoveAt(1);              // {1, 3, 4, 5}

// ๋น ๋ฅธ ์‚ญ์ œ (์ˆœ์„œ ๊นจ์ง) โ€” O(1)
Arr.RemoveAtSwap(1);          // {1, 5, 3, 4}  โ† ๋งˆ์ง€๋ง‰ ์›์†Œ๋ฅผ ๊ทธ ์ž๋ฆฌ์—

์ˆœ์„œ๊ฐ€ ์ค‘์š”ํ•˜์ง€ ์•Š์€ ์ปจํ…Œ์ด๋„ˆ(ํŒŒํ‹ฐํด, ์  ๋ฆฌ์ŠคํŠธ ๋“ฑ)๋Š” RemoveAtSwap์ด ํ›จ์”ฌ ๋น ๋ฆ…๋‹ˆ๋‹ค โ€” ์ด๊ฒŒ ๊ฒŒ์ž„ ์—”์ง„ ์ปจํ…Œ์ด๋„ˆ์˜ ์„ฑ๋Šฅ ๋””ํ…Œ์ผ.

7-4. ์–ธ๋ฆฌ์–ผ์— list ๋Œ€์‘์ด (์‚ฌ์‹ค์ƒ) ์—†๋Š” ์ด์œ 

1
2
3
4
// ํ‘œ์ค€ std::list ์ง์ ‘ ๋Œ€์‘์€ ์—†์Œ
// ํ—ฌํผ ์ˆ˜์ค€์˜ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋Š” ์กด์žฌ:
TLinkedList<T>          // ๋‹จ๋ฐฉํ–ฅ ์—ฐ๊ฒฐ
TDoubleLinkedList<T>    // ์ด์ค‘ ์—ฐ๊ฒฐ

์ด๋“ค์€:

  • intrusive ์Šคํƒ€์ผ์— ๊ฐ€๊น๊ฑฐ๋‚˜ ๋งค์šฐ ๋‹จ์ˆœํ•œ ๊ตฌํ˜„
  • ๊ฒŒ์ž„ ์—”์ง„์ด list๋ฅผ ๊ถŒ์žฅํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฐ•ํ•œ ์˜๋„ ํ‘œํ˜„
  • ๋Œ€๋ถ€๋ถ„ ์ฝ”๋“œ๋Š” TArray ๋˜๋Š” TMap(ํ•ด์‹œ๋งต)์œผ๋กœ ์ž‘์„ฑ๋จ

7-5. ์–ธ๋ฆฌ์–ผ ์ปจํ…Œ์ด๋„ˆ vs STL ์ข…ํ•ฉํ‘œ

์นดํ…Œ๊ณ ๋ฆฌSTL์–ธ๋ฆฌ์–ผ๋น„๊ณ 
๋™์  ๋ฐฐ์—ด (vector)std::vectorTArray1๊ธ‰ ์‹œ๋ฏผ, GC ํ†ตํ•ฉ
์ •์  ๋ฐฐ์—ดstd::arrayTStaticArray์ปดํŒŒ์ผ ํƒ€์ž„ size
์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ (list)std::listTLinkedList (ํ—ฌํผ)1๊ธ‰ ์•„๋‹˜
๋‹จ๋ฐฉํ–ฅ ๋ฆฌ์ŠคํŠธstd::forward_list(์—†์Œ)ย 
๋”๋ธ”์—”๋“œ ํ (deque)std::dequeTQueue, TCircularQueue๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ์•ˆ์ „ ์˜ต์…˜
ํ•ด์‹œ๋งตstd::unordered_mapTMapopen addressing ๋ณ€ํ˜•
ํŠธ๋ฆฌ๋งตstd::map(์—†์Œ, TSortedMap)RB ํŠธ๋ฆฌ ๊ฑฐ์˜ ์•ˆ ์”€
ํ•ด์‹œ์…‹std::unordered_setTSetย 
๋ฌธ์ž์—ดstd::stringFString, FName, FText๋‹ค์ธต ๋ถ„๋ฆฌ
์Šค๋งˆํŠธ ํฌ์ธํ„ฐunique_ptr/shared_ptrTUniquePtr/TSharedPtr11๋ฒˆ ์ฐธ๊ณ 

์–ธ๋ฆฌ์–ผ์€ vectorยทhashmapยทhashset ์ค‘์‹ฌ์ด๊ณ  ํŠธ๋ฆฌ/์—ฐ๊ฒฐ๋ฆฌ์ŠคํŠธ๋Š” ๊ฑฐ์˜ ์“ฐ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๊ฒŒ ๊ฒŒ์ž„ ์—”์ง„์˜ ์บ์‹œ ์นœํ™” ์ฒ ํ•™.

7-6. Algo:: โ€” STL <algorithm> ๋Œ€์‘

1
2
3
4
5
TArray<int32> Arr = {3, 1, 4, 1, 5, 9, 2, 6};

Algo::Sort(Arr);                  // std::sort ๋Œ€์‘
int32* P = Algo::Find(Arr, 5);    // std::find ๋Œ€์‘
Algo::Reverse(Arr);               // std::reverse ๋Œ€์‘

๋‚ด๋ถ€์ ์œผ๋กœ STL๊ณผ ๋™์ผํ•œ ์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜(introsort ๋ณ€ํ˜•)์ด์ง€๋งŒ ์–ธ๋ฆฌ์–ผ ๋ฉ”๋ชจ๋ฆฌ ์‹œ์Šคํ…œ๊ณผ ํ†ตํ•ฉ.


8. ํšŒ๊ท€ ๋‹ค๋ฆฌ โ€” ๋‹ค๋ฅธ CS ํŒŒ์ผ ์—ฐ๊ฒฐ

8-1. 11๋ฒˆ [์Šค๋งˆํŠธ ํฌ์ธํ„ฐ]์™€์˜ ์—ฐ๊ฒฐ

vector<unique_ptr<T>> ํŒจํ„ด

1
2
3
4
5
6
7
8
std::vector<std::unique_ptr<Widget>> widgets;

widgets.push_back(std::make_unique<Widget>(1));
widgets.push_back(std::make_unique<Widget>(2));

// vector ์ž์ฒด๋Š” ํฌ์ธํ„ฐ 8B๋งŒ ์ด๋™ โ€” ์บ์‹œ ์นœํ™” (vector์˜ ์žฅ์ )
// ๊ฐ์ฒด๋Š” ํž™์— ๊ณ ์ • โ€” ํฌ์ธํ„ฐ ์•ˆ์ •์„ฑ (list์˜ ์žฅ์ )
// ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ์—†์Œ โ€” RAII (์Šค๋งˆํŠธ ํฌ์ธํ„ฐ์˜ ์žฅ์ )

์ด ํŒจํ„ด์€ 13๋ฒˆ์—์„œ ๋ณธ โ€œvector์˜ ์บ์‹œ ์นœํ™” + list์˜ ์•ˆ์ •์„ฑ์„ ๋‘˜ ๋‹ค ๊ฐ€์ง€๋Š” ๋ฒ ์ŠคํŠธ ํŒจํ„ดโ€ ์ž…๋‹ˆ๋‹ค.

vector<shared_ptr<T>> ์ฃผ์˜์ 

1
2
std::vector<std::shared_ptr<Widget>> w1 = ...;
std::vector<std::shared_ptr<Widget>> w2 = w1;   // ๋ชจ๋“  ์›์†Œ์˜ atomic refcount++
  • vector ๋ณต์‚ฌ ์‹œ ๋ชจ๋“  ์›์†Œ์˜ ์ฐธ์กฐ ์นด์šดํŠธ๊ฐ€ atomic ์ฆ๊ฐ€ โ†’ ํฐ ๋น„์šฉ
  • shared_ptr์ด atomic์ด๋ผ๋Š” ๋น„์šฉ(11๋ฒˆ)์ด vector ์•ˆ์—์„œ N๋ฐฐ ์ฆํญ๋จ
  • ์ง„์งœ ๊ณต์œ ๊ฐ€ ํ•„์š”ํ•˜๋ฉด vector<shared_ptr>, ์•„๋‹ˆ๋ฉด vector<unique_ptr> ๋˜๋Š” vector<T> ์ง์ ‘

8-2. 12๋ฒˆ [๋ณต์‚ฌ ๊ธˆ์ง€ยทmove-only]์™€์˜ ์—ฐ๊ฒฐ

vector์—์„œ move ์˜๋ฏธ๋ก ์˜ ์ค‘์š”์„ฑ

1
2
3
4
std::vector<Widget> v;
v.reserve(10);
for (int i = 0; i < 1000; ++i)
    v.push_back(Widget());   // ์žฌํ• ๋‹น ์‹œ ๊ธฐ์กด ์›์†Œ๋ฅผ ์ƒˆ ๋ฒ„ํผ๋กœ ์˜ฎ๊ฒจ์•ผ ํ•จ
  • Widget์ด noexcept move ์ƒ์„ฑ์ž๋ฅผ ๊ฐ€์ง€๋ฉด โ†’ vector๊ฐ€ move ์‚ฌ์šฉ โ†’ ๋น ๋ฅด๊ณ  strong guarantee
  • ์—†์œผ๋ฉด โ†’ vector๊ฐ€ ์•ˆ์ „์„ ์œ„ํ•ด copy ์‚ฌ์šฉ โ†’ ๋А๋ฆผ
  • ์ด๊ฒŒ 12๋ฒˆ์—์„œ Rule of Five๊ฐ€ ์ค‘์š”ํ•œ ์ด์œ ์˜ ํ•ต์‹ฌ ์‚ฌ๋ก€
1
2
3
4
5
6
7
8
class Widget {
public:
    Widget(Widget&&) noexcept;             // โ˜… noexcept ํ•„์ˆ˜
    Widget& operator=(Widget&&) noexcept;
    Widget(const Widget&);
    Widget& operator=(const Widget&);
    ~Widget();
};

move-only ํƒ€์ž…์„ ์ปจํ…Œ์ด๋„ˆ์— ๋‹ด๊ธฐ

1
2
3
4
5
std::vector<std::unique_ptr<Widget>> v;   // โœ… move-only OK
std::vector<std::thread> threads;          // โœ… thread๋„ move-only

// std::list๋„ ๊ฐ€๋Šฅ:
std::list<std::unique_ptr<Widget>> l;

unique_ptr(12๋ฒˆ ์ฐธ๊ณ )์€ ๋ณต์‚ฌ ๋ถˆ๊ฐ€์ง€๋งŒ vectorยทlist ๋ชจ๋‘ move๋กœ ์ฒ˜๋ฆฌํ•ด ์ปจํ…Œ์ด๋„ˆ ์•ˆ์— ์ž˜ ๋“ค์–ด๊ฐ‘๋‹ˆ๋‹ค.

8-3. 09๋ฒˆ [RAII]์™€์˜ ์—ฐ๊ฒฐ

vector ์ž์ฒด๊ฐ€ RAII์˜ ์ •์„ ์‚ฌ๋ก€:

1
2
3
4
{
    std::vector<int> v(1'000'000);   // 4MB ์ž๋™ ํ• ๋‹น
    // ... ์‚ฌ์šฉ
}   // ์Šค์ฝ”ํ”„ ์ข…๋ฃŒ โ†’ ์ž๋™ ํ•ด์ œ, ๋ˆ„์ˆ˜ ์—†์Œ
  • ์ƒ์„ฑ์ž์—์„œ ๋ฉ”๋ชจ๋ฆฌ ํš๋“
  • ์†Œ๋ฉธ์ž์—์„œ ๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ (์˜ˆ์™ธ ๋ฐœ์ƒํ•ด๋„ ๋ณด์žฅ)
  • ์‚ฌ์šฉ์ž๊ฐ€ delete[]์„ ํ˜ธ์ถœํ•  ํ•„์š” ์—†์Œ

์ด๊ฒŒ 9๋ฒˆ RAII์™€ 13๋ฒˆ ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ด์–ด์ง€๋Š” ์ง€์ .

8-4. 10๋ฒˆ [๋Œ•๊ธ€๋ง ํฌ์ธํ„ฐ]์™€์˜ ์—ฐ๊ฒฐ

vector ์žฌํ• ๋‹น์ด ๋Œ•๊ธ€๋ง ํฌ์ธํ„ฐ๋ฅผ ๋งŒ๋“œ๋Š” ๊ฐ€์žฅ ํ”ํ•œ ํŒจํ„ด:

1
2
3
4
5
6
7
std::vector<int> v = {1, 2, 3};
int* p = &v[0];                  // p โ†’ v์˜ ์ฒซ ์›์†Œ

v.push_back(4);                  // ์žฌํ• ๋‹น ๊ฐ€๋Šฅ โ€” ์ƒˆ ๋ฒ„ํผ๋กœ ์ด๋™
                                 // p๋Š” ์ด์ œ freed memory ๊ฐ€๋ฆฌํ‚ด โ˜…

*p = 99;                         // โŒ UB โ€” ๋Œ•๊ธ€๋ง ํฌ์ธํ„ฐ ์—ญ์ฐธ์กฐ
  • 10๋ฒˆ์—์„œ ๋ณธ โ€œ์ปจํ…Œ์ด๋„ˆ ์žฌํ• ๋‹น ํ›„ ํฌ์ธํ„ฐ ๋ฌดํšจํ™”โ€ ์˜ ์ •ํ™•ํ•œ ์‚ฌ๋ก€
  • ํ•ด๊ฒฐ: vector<unique_ptr<T>>๋กœ ๊ฐ์ฒด ์•ˆ์ •์„ฑ ํ™•๋ณด (8-1 ์ฐธ๊ณ )

8-5. 04-28(์˜ค๋Š˜) ํšŒ๊ณ  โ€” 12๋ฒˆ โ†’ 13๋ฒˆ ์ž์—ฐ ํ๋ฆ„

์˜ค๋Š˜ 12๋ฒˆ์—์„œ ๋‹ค๋ฃฌ ๊ฐœ๋…์ด 13๋ฒˆ ์ปจํ…Œ์ด๋„ˆ์—์„œ ์–ด๋–ป๊ฒŒ ํ™œ์šฉ๋˜๋Š”๊ฐ€:

1
2
3
4
5
6
7
8
9
12๋ฒˆ ํ•ต์‹ฌ ๊ฐœ๋…                    13๋ฒˆ์—์„œ์˜ ํ™œ์šฉ
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
Rule of Five (move ์ƒ์„ฑ์ž)    โ†’  vector ์žฌํ• ๋‹น ์‹œ move ์‚ฌ์šฉ โ€” ์„ฑ๋Šฅ ๊ฒฐ์ •
move-only ํƒ€์ž… (unique_ptr)   โ†’  vector<unique_ptr<T>> ํŒจํ„ด โ€” ์•ˆ์ •์„ฑ+์บ์‹œ
์•”๋ฌต์  ์‚ญ์ œ                    โ†’  unique_ptr ๋ฉค๋ฒ„๋ฅผ ๊ฐ€์ง„ ํด๋ž˜์Šค๊ฐ€ ์ž๋™
                                  ์œผ๋กœ vector์—์„œ move-only๋กœ ๋™์ž‘
๋ณต์‚ฌ ๊ธˆ์ง€(ํŒŒ์ผ/๋ฎคํ…์Šค/์†Œ์ผ“)    โ†’  vector<ifstream>ยทvector<thread>์ฒ˜๋Ÿผ
                                  move-only ์ปจํ…Œ์ด๋„ˆ ํ™œ์šฉ
RAII (Rule of Zero)            โ†’  vector ์ž์ฒด๊ฐ€ RAII์˜ ๋Œ€ํ‘œ ์‚ฌ๋ก€

13๋ฒˆ์€ 12๋ฒˆ์˜ โ€œ๋ณต์‚ฌยท์ด๋™ ์˜๋ฏธ๋ก โ€์ด ์ปจํ…Œ์ด๋„ˆ์—์„œ ์‹ค์ œ๋กœ ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ๋ณด์—ฌ์ฃผ๋Š” ์‘์šฉํŽธ์ž…๋‹ˆ๋‹ค.


9. ๊ผฌ๋ฆฌ์งˆ๋ฌธ ์˜ˆ์ƒ ๊ฒฝ๋กœ

๋ฉ”์ธ ์งˆ๋ฌธ ๋‹ต๋ณ€ ํ›„ ์˜ˆ์ƒ ํ๋ฆ„

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
"vector์™€ list์˜ ์ฐจ์ด๋Š”?"
         โ”‚
         โ”œโ”€ ๋ฉ”๋ชจ๋ฆฌ ๋ ˆ์ด์•„์›ƒ (์—ฐ์† vs ๋ถ„์‚ฐ)
         โ”‚    โ”œโ”€ "์žฌํ• ๋‹น์€ ์–ด๋–ป๊ฒŒ ์ผ์–ด๋‚˜๋‚˜์š”?"
         โ”‚    โ”‚    โ””โ”€ "์„ฑ์žฅ ์ธ์ž๊ฐ€ 1.5๋ฐฐยท2๋ฐฐ์ธ ์ด์œ ๋Š”?"
         โ”‚    โ””โ”€ "list ๋…ธ๋“œ ํ•˜๋‚˜์˜ ๋ฉ”๋ชจ๋ฆฌ ํฌ๊ธฐ๋Š”?"
         โ”‚
         โ”œโ”€ ์‹œ๊ฐ„ ๋ณต์žก๋„
         โ”‚    โ”œโ”€ "list๋Š” O(1) ์‚ฝ์ž…์ธ๋ฐ ์™œ vector๋ณด๋‹ค ๋А๋ฆฐ๊ฐ€์š”?" โ˜… ํ•จ์ •
         โ”‚    โ”‚    โ””โ”€ "๊ทธ๋Ÿผ list๊ฐ€ ๋” ๋น ๋ฅธ ๊ฒฝ์šฐ๋Š” ์ •๋ง ์—†๋‚˜์š”?"
         โ”‚    โ””โ”€ "amortized O(1)์ด ์ •ํ™•ํžˆ ๋ญ”๊ฐ€์š”?"
         โ”‚
         โ”œโ”€ CPU ์บ์‹œ (โ˜… ๊ฐ€์žฅ ๊นŠ์ด ๋“ค์–ด๊ฐˆ ๊ฐ€๋Šฅ์„ฑ ๋†’์Œ)
         โ”‚    โ”œโ”€ "์บ์‹œ ๋ผ์ธ์ด ๋ญ”๊ฐ€์š”?"
         โ”‚    โ”‚    โ””โ”€ "๊ณต๊ฐ„ ์ง€์—ญ์„ฑ๊ณผ ์‹œ๊ฐ„ ์ง€์—ญ์„ฑ์˜ ์ฐจ์ด๋Š”?"
         โ”‚    โ”œโ”€ "ํ”„๋ฆฌํŽ˜์ฒ˜๊ฐ€ ๋ญ”๊ฐ€์š”?"
         โ”‚    โ”‚    โ””โ”€ "list์—์„œ๋Š” ์™œ ์ž‘๋™ํ•˜์ง€ ์•Š๋‚˜์š”?"
         โ”‚    โ””โ”€ "L1ยทL2ยทL3 ์ฐจ์ด?"
         โ”‚
         โ”œโ”€ iterator ๋ฌดํšจํ™”
         โ”‚    โ”œโ”€ "vector์—์„œ push_back ํ›„ iterator ์‚ฌ์šฉ์€ ์•ˆ์ „ํ•œ๊ฐ€์š”?"
         โ”‚    โ””โ”€ "list๊ฐ€ iterator ์•ˆ์ •์„ฑ์ด ๊ฐ•ํ•œ ์ด์œ ๋Š”?"
         โ”‚
         โ”œโ”€ ์˜ˆ์™ธ ์•ˆ์ „์„ฑ
         โ”‚    โ””โ”€ "vector ์žฌํ• ๋‹น ์‹œ noexcept ์ด๋™์ด ์™œ ์ค‘์š”ํ•œ๊ฐ€์š”?" โ˜… 12๋ฒˆ ํšŒ๊ท€
         โ”‚
         โ”œโ”€ ์–ธ์ œ list?
         โ”‚    โ”œโ”€ "deque์™€ ์–ด๋–ค ์ฐจ์ด๊ฐ€ ์žˆ๋‚˜์š”?"
         โ”‚    โ””โ”€ "vector<unique_ptr<T>>๊ฐ€ list ๋Œ€์•ˆ์ธ ์ด์œ ๋Š”?" โ˜… 11๋ฒˆ ํšŒ๊ท€
         โ”‚
         โ””โ”€ ์–ธ๋ฆฌ์–ผ
              โ”œโ”€ "TArray์™€ std::vector์˜ ์ฐจ์ด๋Š”?"
              โ”œโ”€ "RemoveAt vs RemoveAtSwap?"
              โ””โ”€ "์™œ ์–ธ๋ฆฌ์–ผ์€ list ๋Œ€์‘์„ 1๊ธ‰์œผ๋กœ ๋‘์ง€ ์•Š๋‚˜์š”?"

๊ฐ ๊ผฌ๋ฆฌ์งˆ๋ฌธ 30์ดˆ ๋‹ต๋ณ€

Q: vector์™€ list์˜ ๊ฐ€์žฅ ํฐ ์ฐจ์ด๋Š”?

1
2
3
4
5
6
๋ฉ”๋ชจ๋ฆฌ ๋ ˆ์ด์•„์›ƒ:
  vector โ€” ์—ฐ์† ๋ฉ”๋ชจ๋ฆฌ ๋™์  ๋ฐฐ์—ด
  list   โ€” ๋…ธ๋“œ๊ฐ€ ํž™์— ๋ถ„์‚ฐ, prev/next ํฌ์ธํ„ฐ๋กœ ์—ฐ๊ฒฐ

์ด ์ฐจ์ด๊ฐ€ ์บ์‹œ ์นœํ™”์„ฑ์„ ๊ฒฐ์ •ํ•ด ์‹ค์ธก ์„ฑ๋Šฅ์„ 100๋ฐฐ๊นŒ์ง€ ๊ฐ€๋ฅด๊ณ ,
์ด๋ก  ์‹œ๊ฐ„ ๋ณต์žก๋„๊ฐ€ ๊ฐ™์•„๋„ vector๊ฐ€ ๊ฑฐ์˜ ํ•ญ์ƒ ๋น ๋ฅธ ์ด์œ .

Q: list์˜ O(1) ์ค‘๊ฐ„ ์‚ฝ์ž…์ด ์™œ ์‹ค์ œ๋กœ vector๋ณด๋‹ค ๋А๋ฆฐ๊ฐ€์š”?

1
2
3
4
5
6
7
8
์„ธ ๊ฐ€์ง€ ์ด์œ :
1) ์œ„์น˜ iterator๋ฅผ ์†์— ๋“ค๊ณ  ์žˆ์–ด์•ผ๋งŒ O(1) โ€” ์—†์œผ๋ฉด find๊ฐ€ O(n)
2) ์ƒˆ ๋…ธ๋“œ ํ• ๋‹น์ด operator new ํ˜ธ์ถœ (์ˆ˜์‹ญ~์ˆ˜๋ฐฑ ns) + ์บ์‹œ ๋ฏธ์Šค
3) vector์˜ memmove๋Š” SIMD๋กœ ํ•œ ๋ฒˆ์— ์—ฌ๋Ÿฌ ๋ฐ”์ดํŠธ ์ด๋™, ๊ฒŒ๋‹ค๊ฐ€
   ๋ฐ์ดํ„ฐ๊ฐ€ ์บ์‹œ์— ์ด๋ฏธ ์˜ฌ๋ผ์™€ ์žˆ์–ด ์‚ฌ์‹ค์ƒ ๋ฌด๋ฃŒ

๊ฒฐ๋ก : N์ด ์ˆ˜๋งŒ~์ˆ˜์‹ญ๋งŒ ์ดํ•˜๋ฉด vector ์••์Šน,
      ๊ทธ ์ด์ƒ๋„ ์บ์‹œ ํšจ์œจ๋กœ vector๊ฐ€ ์ด๊ธฐ๋Š” ๊ฒฝ์šฐ ๋Œ€๋ถ€๋ถ„.

Q: ์บ์‹œ ๋ผ์ธ์ด ์ •ํ™•ํžˆ ๋ญ”๊ฐ€์š”?

1
2
3
4
5
6
7
CPU๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๊ฐ€์ ธ์˜ฌ ๋•Œ ํ•œ ๋ฐ”์ดํŠธ์”ฉ ๊ฐ€์ ธ์˜ค์ง€ ์•Š๊ณ 
์ผ์ • ๋‹จ์œ„๋กœ ๊ฐ€์ ธ์˜ค๋Š”๋ฐ, ๊ทธ ๋‹จ์œ„๊ฐ€ ์บ์‹œ ๋ผ์ธ.
x86_64์—์„œ๋Š” ๋ณดํ†ต 64๋ฐ”์ดํŠธ.

ํ•œ ๋ฒˆ ๊ฐ€์ ธ์˜จ ๋ผ์ธ ์•ˆ์˜ ๋‹ค๋ฅธ ๋ฐ์ดํ„ฐ๋Š” ๊ฑฐ์˜ ๋ฌด๋ฃŒ(L1 ~1ns)๋กœ ์ ‘๊ทผ.
vector๋Š” 64๋ฐ”์ดํŠธ ์•ˆ์— int 16๊ฐœ๊ฐ€ ๋“ค์–ด์™€ ์ฒซ ๋ฏธ์Šค ํ›„ 15๊ฐœ๋Š” ์บ์‹œ ํžˆํŠธ.
list๋Š” ๋…ธ๋“œ๊ฐ€ ๋ถ„์‚ฐ๋ผ ๋งค ๋…ธ๋“œ๋งˆ๋‹ค ์ƒˆ ๋ผ์ธ ๋กœ๋“œ โ†’ ์บ์‹œ ๋ฏธ์Šค ํญํƒ„.

Q: ํ”„๋ฆฌํŽ˜์ฒ˜๊ฐ€ ๋ญ”๊ฐ€์š”?

1
2
3
4
5
6
7
8
9
CPU์— ๋‚ด์žฅ๋œ ํšŒ๋กœ๋กœ, ๋ฉ”๋ชจ๋ฆฌ ์ ‘๊ทผ ํŒจํ„ด์„ ๊ฐ์ง€ํ•ด
๋‹ค์Œ์— ํ•„์š”ํ•  ์บ์‹œ ๋ผ์ธ์„ ๋ฏธ๋ฆฌ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

vector ์ˆœํšŒ: ๋ผ์ธ N โ†’ N+1 โ†’ N+2 ... ์ˆœ์ฐจ ํŒจํ„ด ๊ฐ์ง€ โ†’
             ๋‹ค์Œ ๋ผ์ธ์„ ๋ฏธ๋ฆฌ ๋กœ๋“œํ•ด ๋ฉ”๋ชจ๋ฆฌ ์ง€์—ฐ์ด ์‚ฌ์‹ค์ƒ ์‚ฌ๋ผ์ง
list ์ˆœํšŒ:   ๋…ธ๋“œ next ํฌ์ธํ„ฐ๊ฐ€ ๋ฌด์ž‘์œ„ ์ฃผ์†Œ โ†’ ํŒจํ„ด ์—†์Œ โ†’
             ํ”„๋ฆฌํŽ˜์ฒ˜ ๋ฌด๋ ฅ โ†’ DRAM 100ns ร— N๋ฒˆ ๊ทธ๋Œ€๋กœ ๋ถ€๋‹ด

vector๊ฐ€ ๋น ๋ฅธ ์ด์œ ์˜ ์ ˆ๋ฐ˜์€ ํ”„๋ฆฌํŽ˜์ฒ˜ ๋•๋ถ„.

Q: amortized O(1)์ด ๋ญ”๊ฐ€์š”?

1
2
3
4
5
6
7
8
9
10
"ํ‰๊ท ์ ์œผ๋กœ O(1)์ด์ง€๋งŒ ๊ฐ€๋” O(n) ๋น„์šฉ์ด ๋“œ๋Š”" ์—ฐ์‚ฐ.

vector::push_back์€:
  - ๋Œ€๋ถ€๋ถ„ O(1) (capacity ์—ฌ์œ  ์žˆ์„ ๋•Œ)
  - ๊ฐ€๋” O(n) (์žฌํ• ๋‹น ๋ฐœ์ƒ ์‹œ ๋ชจ๋“  ์›์†Œ ์ด๋™)

์„ฑ์žฅ ์ธ์ž๊ฐ€ 2๋ฐฐ๋ผ N๊ฐœ push_back ๋ˆ„์  ๋น„์šฉ์ด O(2N) = O(N).
ํ•œ ๋ฒˆ ํ‰๊ท ํ•˜๋ฉด O(1) โ€” ๋ถ„ํ•  ์ƒํ™˜(amortized) ๋ถ„์„.

reserve๋กœ ๋ฏธ๋ฆฌ capacity๋ฅผ ์žก์œผ๋ฉด ์ง„์งœ O(1) ๋ณด์žฅ.

Q: vector iterator๋Š” ์–ธ์ œ ๋ฌดํšจํ™”๋˜๋‚˜์š”?

1
2
3
4
5
6
7
8
9
10
11
์žฌํ• ๋‹น ์‹œ ๋ชจ๋“  iterator/ํฌ์ธํ„ฐ/์ฐธ์กฐ ๋ฌดํšจํ™”:
  push_back, emplace_back, insert (capacity ์ดˆ๊ณผ ์‹œ)
  reserve (n > capacity)
  resize, shrink_to_fit

๋ถ€๋ถ„ ๋ฌดํšจํ™”:
  insert/erase (์žฌํ• ๋‹น ์—†์„ ๋•Œ) โ†’ ํ•ด๋‹น ์œ„์น˜ ์ดํ›„ ๋ฌดํšจ
  clear โ†’ ๋ชจ๋‘

list๋Š” ์‚ญ์ œ๋œ ๋…ธ๋“œ๋งŒ ๋ฌดํšจํ™”๋ผ splice/merge ๊ฐ™์€ ์—ฐ์‚ฐ์ด ์•ˆ์ „.
์ด๊ฒŒ list์˜ ๊ฐ€์žฅ ์ •์งํ•œ ๊ฐ•์ .

**Q: vector์—์„œ T์˜ noexcept move๊ฐ€ ์™œ ์ค‘์š”ํ•œ๊ฐ€์š”?** (โ˜… 12๋ฒˆ ํšŒ๊ท€)

1
2
3
4
5
6
7
8
9
10
11
์žฌํ• ๋‹น ์‹œ vector๋Š” ๊ธฐ์กด ์›์†Œ๋ฅผ ์ƒˆ ๋ฒ„ํผ๋กœ ์˜ฎ๊ฒจ์•ผ ํ•จ.

T๊ฐ€ noexcept move๋ฅผ ๊ฐ€์ง€๋ฉด:
  โ†’ vector๊ฐ€ move ์‚ฌ์šฉ โ†’ ๋น ๋ฅด๊ณ  strong exception guarantee
T์˜ move๊ฐ€ throw ๊ฐ€๋Šฅํ•˜๋ฉด:
  โ†’ vector๊ฐ€ ์•ˆ์ „์„ ์œ„ํ•ด copy ์‚ฌ์šฉ โ†’ ๋А๋ฆผ
T์˜ copy๋„ throwํ•˜๋ฉด:
  โ†’ basic guarantee๋กœ ๊ฐ•๋“ฑ

๋”ฐ๋ผ์„œ ์‚ฌ์šฉ์ž ์ •์˜ ํด๋ž˜์Šค๋Š” ํ•ญ์ƒ noexcept move๋ฅผ ์ •์˜ํ•˜๋Š” ๊ฒŒ ์ข‹์Œ.
์ด๊ฒŒ 12๋ฒˆ Rule of Five์˜ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ์‘์šฉ ์‚ฌ๋ก€.

Q: list๊ฐ€ ์ •๋ง ํ•„์š”ํ•œ ๊ฒฝ์šฐ๋Š” ์–ธ์ œ์ธ๊ฐ€์š”?

1
2
3
4
5
6
7
8
9
10
11
12
13
๊ทนํžˆ ๋“œ๋ฌธ ์ผ€์ด์Šค (5์กฐ๊ฑด ๋ชจ๋‘ ๋งŒ์กฑ):
1) ๋งค์šฐ ํฐ ๊ฐ์ฒด (์ˆ˜ KB ์ด์ƒ)
2) ์žฆ์€ splice/merge
3) iterator/ํฌ์ธํ„ฐ ์•ˆ์ •์„ฑ์ด ํ•„์ˆ˜
4) ๊ฒ€์ƒ‰์€ ๊ฑฐ์˜ ์•ˆ ํ•จ
5) ๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ์€ ์‹ ๊ฒฝ ์•ˆ ์”€

ํ•˜๋‚˜๋ผ๋„ ๋น ์ง€๋ฉด ๋ณดํ†ต ๋‹ค๋ฅธ ์ž๋ฃŒ๊ตฌ์กฐ๊ฐ€ ๋” ๋‚˜์Œ:
  - ์บ์‹œ๋Š” ์‹ ๊ฒฝ X but ์•ˆ์ •์„ฑ ํ•„์š” โ†’ vector<unique_ptr<T>>
  - ์–‘์ชฝ push ํ•„์š” โ†’ std::deque
  - ๋‹จ๋ฐฉํ–ฅ + ๋ฉ”๋ชจ๋ฆฌ ์ ˆ์•ฝ โ†’ std::forward_list

Stroustrup: "์˜์‹ฌ์Šค๋Ÿฌ์šฐ๋ฉด vector. ๊ทธ๋ž˜๋„ ์˜์‹ฌ์Šค๋Ÿฌ์šฐ๋ฉด ๊ทธ๋ž˜๋„ vector."

Q: deque์™€ list์˜ ์ฐจ์ด๋Š”?

1
2
3
4
5
6
7
8
9
10
11
12
13
deque (Double-Ended Queue):
  - ์ฒญํฌ ๊ธฐ๋ฐ˜ (๋ณดํ†ต 4KB ์ฒญํฌ ์—ฌ๋Ÿฌ ๊ฐœ๋ฅผ ์ธ๋ฑ์Šค ๋ฐฐ์—ด๋กœ ๊ด€๋ฆฌ)
  - push_front O(1), push_back O(1), ์ž„์˜ ์ ‘๊ทผ O(1)
  - ์ฒญํฌ ์•ˆ์—์„œ ์—ฐ์† ๋ฉ”๋ชจ๋ฆฌ โ†’ ์บ์‹œ ์นœํ™” (vector๋ณด๋‹ค ์•ฝ๊ฐ„ ๋ชปํ•จ)
  - iterator๋Š” front/back push ์‹œ ์•ˆ์ • (vector์™€ ๋‹ค๋ฅธ ์ )

list:
  - ๋…ธ๋“œ๋ณ„ ๋ถ„์‚ฐ ํ• ๋‹น
  - ์ž„์˜ ์ ‘๊ทผ O(n)
  - ์บ์‹œ ์ ๋Œ€

deque๋Š” "vector + ์–‘์ชฝ push"์ด๊ณ , list๋Š” "iterator ์•ˆ์ •์„ฑ + ๋…ธ๋“œ splice"
๋Œ€๋ถ€๋ถ„ ์‚ฌ์šฉ ์‚ฌ๋ก€์—์„œ deque > list.

Q: TArray์™€ std::vector์˜ ์ฐจ์ด๋Š”?

1
2
3
4
5
6
7
8
9
10
๊ฑฐ์˜ ๊ฐ™์Œ โ€” ๋‘˜ ๋‹ค ์—ฐ์† ๋ฉ”๋ชจ๋ฆฌ ๋™์  ๋ฐฐ์—ด, ์„ฑ์žฅ ์ธ์ž 1.5x~2x.

์–ธ๋ฆฌ์–ผ ์ถ”๊ฐ€ ๊ธฐ๋Šฅ:
  - UPROPERTY()๋กœ GC ํ†ตํ•ฉ โ€” TArray<UItem*> ์•ˆ์˜ UObject๋„ GC๊ฐ€ ์ถ”์ 
  - ๋ธ”๋ฃจํ”„๋ฆฐํŠธยท๋””ํ…Œ์ผ ํŒจ๋„ยทreplication ์ž๋™ ์ง€์›
  - RemoveAtSwap โ€” ์ˆœ์„œ ๋ฌด์‹œํ•˜๊ณ  O(1) ์‚ญ์ œ (๋งˆ์ง€๋ง‰ ์›์†Œ์™€ swap)
  - GetAllocator๋กœ ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น์ž ์ปค์Šคํ„ฐ๋งˆ์ด์ง•
  - ์–ธ๋ฆฌ์–ผ ๋ฉ”๋ชจ๋ฆฌ ์‹œ์Šคํ…œ(FMemory) ํ†ตํ•ฉ

UObject ํฌ์ธํ„ฐ ์ปจํ…Œ์ด๋„ˆ๋Š” std::vector๊ฐ€ ์•„๋‹ˆ๋ผ ๋ฐ˜๋“œ์‹œ TArray + UPROPERTY.

Q: ์–ธ๋ฆฌ์–ผ์€ ์™œ list ๋Œ€์‘์„ ์•ˆ ๋‘๋‚˜์š”?

1
2
3
4
5
6
7
8
9
10
11
๊ฒŒ์ž„ ์—”์ง„์€ ๋งค ํ”„๋ ˆ์ž„ ์ˆ˜๋งŒ~์ˆ˜์‹ญ๋งŒ ๊ฐœ ๊ฐ์ฒด๋ฅผ ์ˆœํšŒ.
์บ์‹œ ๋ฏธ์Šค 100ns ร— ๋งŒ ๊ฐœ = 1ms์”ฉ ์ƒˆ๋Š” ์…ˆ โ†’ 60FPS(16.6ms) ์˜ˆ์‚ฐ ์••๋ฐ•.

๋”ฐ๋ผ์„œ ์–ธ๋ฆฌ์–ผ์€:
  - TArray (vector ๋Œ€์‘) 1๊ธ‰ ์‹œ๋ฏผ
  - TMapยทTSet (ํ•ด์‹œ ์ปจํ…Œ์ด๋„ˆ) 1๊ธ‰ ์‹œ๋ฏผ
  - TLinkedListยทTDoubleLinkedList โ€” 1๊ธ‰์ด ์•„๋‹Œ ํ—ฌํผ ์ˆ˜์ค€
  - ํŠธ๋ฆฌยทBST ์ปจํ…Œ์ด๋„ˆ ๊ฑฐ์˜ ์—†์Œ (์บ์‹œ ์ ๋Œ€์ )

ECSยทSoA ํŒจํ„ด(Entity Component System)๋„ ๊ฐ™์€ ์บ์‹œ ์ฒ ํ•™.
"์บ์‹œ ์นœํ™” โ‰’ ๊ฒŒ์ž„ ์„ฑ๋Šฅ"์ด ์—”์ง„ ์„ค๊ณ„ ์ „๋ฐ˜์— ๊น”๋ฆฐ ์›์น™.

10. ๋ชจ์˜๋ฉด์ ‘ ๋‹ต๋ณ€ ํ…œํ”Œ๋ฆฟ (1๋ถ„ / 3๋ถ„)

10-1. 1๋ถ„ ๋ฒ„์ „ โ€” ํ•ต์‹ฌ๋งŒ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
vector์™€ list๋Š” ๋‘˜ ๋‹ค ์‹œํ€€์Šค ์ปจํ…Œ์ด๋„ˆ์ง€๋งŒ ๋ฉ”๋ชจ๋ฆฌ ๋ ˆ์ด์•„์›ƒ์ด ์ •๋ฐ˜๋Œ€์ž…๋‹ˆ๋‹ค.

vector๋Š” ์—ฐ์† ๋ฉ”๋ชจ๋ฆฌ ๋™์  ๋ฐฐ์—ด์ด๊ณ , list๋Š” ๋…ธ๋“œ๊ฐ€ ํž™์— ๋ถ„์‚ฐ๋œ ์ด์ค‘ ์—ฐ๊ฒฐ
๋ฆฌ์ŠคํŠธ์ž…๋‹ˆ๋‹ค. ์‹œ๊ฐ„ ๋ณต์žก๋„๋งŒ ๋ณด๋ฉด list๊ฐ€ ์ค‘๊ฐ„ ์‚ฝ์ž… O(1)๋กœ ์œ ๋ฆฌํ•ด ๋ณด์ด์ง€๋งŒ,
์‹ค์ธก ์„ฑ๋Šฅ์€ ๊ฑฐ์˜ ๋ชจ๋“  ์›Œํฌ๋กœ๋“œ์—์„œ vector๊ฐ€ ์••์Šนํ•ฉ๋‹ˆ๋‹ค.

์ด์œ ๋Š” CPU ์บ์‹œ์ž…๋‹ˆ๋‹ค. CPU๋Š” ๋ฉ”๋ชจ๋ฆฌ๋ฅผ 64๋ฐ”์ดํŠธ ์บ์‹œ ๋ผ์ธ ๋‹จ์œ„๋กœ ๊ฐ€์ ธ์˜ค๋Š”๋ฐ,
vector๋Š” ํ•œ ๋ผ์ธ์— ์›์†Œ๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐœ ๋“ค์–ด์˜ค๊ณ  ํ”„๋ฆฌํŽ˜์ฒ˜๊ฐ€ ๋‹ค์Œ ๋ผ์ธ์„ ๋ฏธ๋ฆฌ
๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค. list๋Š” ๋…ธ๋“œ๊ฐ€ ๋ถ„์‚ฐ๋ผ ๋งค ๋…ธ๋“œ๋งˆ๋‹ค ์บ์‹œ ๋ฏธ์Šค๊ฐ€ ๋‚˜์„œ, 1M๊ฐœ ์ˆœํšŒ
๋ฒค์น˜๋งˆํฌ์—์„œ vector ~1ms, list ~100ms โ€” 100๋ฐฐ ์ฐจ์ด๊ฐ€ ๋‚ฉ๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ํ˜„๋Œ€ ํ•˜๋“œ์›จ์–ด์—์„œ๋Š” ๊ฑฐ์˜ ํ•ญ์ƒ vector๊ฐ€ ์ •๋‹ต์ด๊ณ , list๋Š” "๋งค์šฐ ํฐ
๊ฐ์ฒด + ์žฆ์€ splice + iterator ์•ˆ์ •์„ฑ ํ•„์ˆ˜"๋ผ๋Š” ์ข์€ ๊ฒฝ์šฐ์—๋งŒ ์ •๋‹นํ™”๋ฉ๋‹ˆ๋‹ค.
์˜์‹ฌ์Šค๋Ÿฌ์šฐ๋ฉด vector๋ฅผ ์“ฐ๊ณ , ๊ทธ๋ž˜๋„ ์˜์‹ฌ์Šค๋Ÿฌ์šฐ๋ฉด ๊ทธ๋ž˜๋„ vector๋ฅผ ์“ฐ๋ผ๋Š” ๊ฒŒ
Stroustrup์ด ์ง์ ‘ ๊ถŒ๊ณ ํ•˜๋Š” ๋ฃฐ์ž…๋‹ˆ๋‹ค.

10-2. 3๋ถ„ ๋ฒ„์ „ โ€” ์บ์‹œยทiteratorยท์–ธ๋ฆฌ์–ผ๊นŒ์ง€

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
[1] ๋ฉ”๋ชจ๋ฆฌ ๋ ˆ์ด์•„์›ƒ๋ถ€ํ„ฐ ์ •๋ฐ˜๋Œ€์ž…๋‹ˆ๋‹ค.

vector๋Š” ์—ฐ์† ๋ฉ”๋ชจ๋ฆฌ ๋™์  ๋ฐฐ์—ด์ž…๋‹ˆ๋‹ค. capacity๊ฐ€ ๋ถ€์กฑํ•˜๋ฉด ๋ณดํ†ต 1.5๋ฐฐ(MSVC)
๋‚˜ 2๋ฐฐ(libstdc++)๋กœ ์žฌํ• ๋‹นํ•˜๋ฉด์„œ ๋ชจ๋“  ์›์†Œ๋ฅผ ์ƒˆ ๋ฒ„ํผ๋กœ ์˜ฎ๊น๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ
push_back์€ amortized O(1) โ€” ํ‰๊ท ์€ O(1)์ด์ง€๋งŒ ๊ฐ€๋” O(n) ๋น„์šฉ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
๋ฏธ๋ฆฌ reserve๋กœ capacity๋ฅผ ์žก์œผ๋ฉด ์žฌํ• ๋‹น ์—†์ด ์ง„์งœ O(1)์ด ๋ฉ๋‹ˆ๋‹ค.

list๋Š” ์ด์ค‘ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋กœ, ๊ฐ ๋…ธ๋“œ๊ฐ€ ํž™์— ๋”ฐ๋กœ ํ• ๋‹น๋˜๊ณ  prevยทnext ํฌ์ธํ„ฐ๋กœ
์—ฐ๊ฒฐ๋ฉ๋‹ˆ๋‹ค. ๋…ธ๋“œ ํ•˜๋‚˜์— prev 8B + next 8B + ๋ฐ์ดํ„ฐ + ํž™ ํ—ค๋” ์•ฝ 16B โ€”
int 4๋ฐ”์ดํŠธ๋ฅผ ์œ„ํ•ด 40๋ฐ”์ดํŠธ ๋…ธ๋“œ๋ฅผ ๋งŒ๋“œ๋Š” ์…ˆ์ž…๋‹ˆ๋‹ค. 1M๊ฐœ int๋ฅผ ๋‹ด์œผ๋ฉด
vector๋Š” 4MB, list๋Š” 40MB ์ •๋„ โ€” ๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ์ด 10๋ฐฐ ์ฐจ์ด ๋‚ฉ๋‹ˆ๋‹ค.

[2] ์‹œ๊ฐ„ ๋ณต์žก๋„๋Š” ํ•จ์ •์ด ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋ก ์ƒ list๊ฐ€ ์ค‘๊ฐ„ ์‚ฝ์ž… O(1)๋กœ ์œ ๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๊ทธ O(1)์€ ์œ„์น˜ iterator๋ฅผ
์ด๋ฏธ ์†์— ๋“ค๊ณ  ์žˆ์„ ๋•Œ ์–˜๊ธฐ๊ณ , ์‹ค์ œ๋กœ๋Š” ๊ฐ’์„ find๋กœ ์ฐพ์•„์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€
๋Œ€๋ถ€๋ถ„์ด๋ผ ๊ฒฐ๊ตญ O(n)์ž…๋‹ˆ๋‹ค. ๊ฒŒ๋‹ค๊ฐ€ ์ƒˆ ๋…ธ๋“œ ํ• ๋‹น์— operator new ํ˜ธ์ถœ๊ณผ
์บ์‹œ ๋ฏธ์Šค๊ฐ€ ๋”ฐ๋ผ์˜ต๋‹ˆ๋‹ค.

vector์˜ ์ค‘๊ฐ„ ์‚ฝ์ž…์€ ์ด๋ก ์ƒ O(n)์ด์ง€๋งŒ memmove๊ฐ€ SIMD๋กœ ํ•œ ๋ฒˆ์— ์—ฌ๋Ÿฌ
๋ฐ”์ดํŠธ์”ฉ ์˜ฎ๊ธฐ๊ณ , ๋ฐ์ดํ„ฐ๊ฐ€ ์ด๋ฏธ ์บ์‹œ์— ์žˆ์–ด ๊ฑฐ์˜ ๋ฌด๋ฃŒ์ž…๋‹ˆ๋‹ค. Stroustrup์˜
์œ ๋ช…ํ•œ ๊ฐ•์—ฐ์—์„œ N๊ฐœ ๋ฌด์ž‘์œ„ ์œ„์น˜ ์‚ฝ์ž… ๋ฒค์น˜๋งˆํฌ๋ฅผ ๋ณด๋ฉด, N์ด 50๋งŒ์ผ ๋•Œ
vector๋Š” 1.1์ดˆ, list๋Š” 35์ดˆ โ€” 30๋ฐฐ ์ฐจ์ด๋กœ vector๊ฐ€ ์ด๊น๋‹ˆ๋‹ค.

[3] ํ•ต์‹ฌ์€ CPU ์บ์‹œ์ž…๋‹ˆ๋‹ค.

ํ˜„๋Œ€ CPU๋Š” ๋ฉ”๋ชจ๋ฆฌ๋ณด๋‹ค 100๋ฐฐ ๋น ๋ฅด๊ณ , ๊ทธ ๊ฒฉ์ฐจ๋ฅผ ์บ์‹œ๋กœ ๋ฉ”์›๋‹ˆ๋‹ค. L1์€ ์•ฝ
1ns, L2๋Š” 3ns, L3๋Š” 12ns, DRAM์€ 100ns๋กœ 4๋‹จ๊ณ„์ž…๋‹ˆ๋‹ค. CPU๋Š” ๋ฉ”๋ชจ๋ฆฌ๋ฅผ
ํ•œ ๋ฐ”์ดํŠธ์”ฉ์ด ์•„๋‹ˆ๋ผ 64๋ฐ”์ดํŠธ ์บ์‹œ ๋ผ์ธ ๋‹จ์œ„๋กœ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ํ•œ
๋ผ์ธ์„ ๊ฐ€์ ธ์˜ค๋ฉด ๊ทธ ์•ˆ์˜ ๋‹ค๋ฅธ ๋ฐ์ดํ„ฐ๋Š” ๊ฑฐ์˜ ๊ณต์งœ์ž…๋‹ˆ๋‹ค.

vector๋Š” ์—ฐ์† ๋ฉ”๋ชจ๋ฆฌ๋ผ ํ•œ ๋ผ์ธ์— int๊ฐ€ 16๊ฐœ ๋“ค์–ด์˜ค๊ณ , ํ•˜๋“œ์›จ์–ด ํ”„๋ฆฌํŽ˜์ฒ˜๊ฐ€
์ˆœ์ฐจ ํŒจํ„ด์„ ๊ฐ์ง€ํ•ด ๋‹ค์Œ ๋ผ์ธ์„ ๋ฏธ๋ฆฌ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. ๊ฒฐ๊ณผ์ ์œผ๋กœ ๋ฉ”๋ชจ๋ฆฌ ์ง€์—ฐ์ด
์‚ฌ์‹ค์ƒ ์‚ฌ๋ผ์ง‘๋‹ˆ๋‹ค. list๋Š” ๋…ธ๋“œ๊ฐ€ ๋ฌด์ž‘์œ„ ์ฃผ์†Œ์— ๋ถ„์‚ฐ๋ผ ๋งค ๋…ธ๋“œ๋งˆ๋‹ค ์ƒˆ
๋ผ์ธ์„ ๊ฐ€์ ธ์™€์•ผ ํ•˜๊ณ  ํ”„๋ฆฌํŽ˜์ฒ˜๋„ ๋ฌด๋ ฅํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ 1M ์ˆœํšŒ ์‹œ ์บ์‹œ
๋ฏธ์Šค๊ฐ€ ์•ฝ 1M๋ฒˆ ์ผ์–ด๋‚˜ 100ms๋ฅผ ๊ทธ๋Œ€๋กœ ๋ถ€๋‹ดํ•ฉ๋‹ˆ๋‹ค.

์ด๋ก  ๋ณต์žก๋„๊ฐ€ ๊ฐ™์•„๋„ ์บ์‹œ ์นœํ™”์„ฑ์ด ์‹ค์ธก ์„ฑ๋Šฅ์„ ๊ฒฐ์ •ํ•œ๋‹ค โ€” ์ด๊ฒŒ 13๋ฒˆ
์ฃผ์ œ์˜ ํ•ต์‹ฌ ๋ฉ”์‹œ์ง€์ž…๋‹ˆ๋‹ค.

[4] iterator ๋ฌดํšจํ™”๋„ ๋‹ค๋ฆ…๋‹ˆ๋‹ค.

vector๋Š” ์žฌํ• ๋‹น ์‹œ ๋ชจ๋“  iteratorยทํฌ์ธํ„ฐยท์ฐธ์กฐ๊ฐ€ ๋ฌดํšจํ™”๋ฉ๋‹ˆ๋‹ค. ์ค‘๊ฐ„
insert/erase๋Š” ๊ทธ ์œ„์น˜ ์ดํ›„๊ฐ€ ๋ฌดํšจํ™”๋ฉ๋‹ˆ๋‹ค. list๋Š” ์‚ญ์ œ๋œ ๋…ธ๋“œ ์ž์‹ ๋งŒ
๋ฌดํšจํ™”๋˜๊ณ  ๋‹ค๋ฅธ ๋…ธ๋“œ๋Š” ์•ˆ์ „ํ•ด spliceยทmerge ๊ฐ™์€ ๋…ธ๋“œ ์žฌ๋ฐฐ์น˜๊ฐ€ ๊น”๋”ํ•ฉ๋‹ˆ๋‹ค.
์ด๊ฒŒ list์˜ ๊ฑฐ์˜ ์œ ์ผํ•œ ์ •์งํ•œ ๊ฐ•์ ์ž…๋‹ˆ๋‹ค.

์˜ˆ์™ธ ์•ˆ์ „์„ฑ ๋ฉด์—์„œ๋„ list๋Š” push ์—ฐ์‚ฐ์ด ์ž๋™์œผ๋กœ strong guarantee์ด๊ณ ,
vector๋Š” noexcept ์ด๋™ ์ƒ์„ฑ์ž๊ฐ€ ์žˆ์–ด์•ผ ํšจ์œจ์ ์ธ strong guarantee๋ฅผ
์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์‚ฌ์šฉ์ž ์ •์˜ ํด๋ž˜์Šค๋Š” ํ•ญ์ƒ noexcept move๋ฅผ ์ •์˜ํ•˜๋Š”
๊ฒŒ ์ข‹์Šต๋‹ˆ๋‹ค โ€” Rule of Five์—์„œ ๋‹ค๋ฃฌ ๊ทธ ์ง€์ ์ž…๋‹ˆ๋‹ค.

[5] ๊ฒฐ๋ก ๊ณผ ์–ธ๋ฆฌ์–ผ.

ํ˜„๋Œ€ ํ•˜๋“œ์›จ์–ด์—์„œ list๋Š” ๊ฑฐ์˜ ํ•ญ์ƒ ์ž˜๋ชป๋œ ์„ ํƒ์ž…๋‹ˆ๋‹ค. ๋งค์šฐ ํฐ ๊ฐ์ฒด์—
์žฆ์€ splice๊ฐ€ ํ•„์š”ํ•˜๊ณ  iterator ์•ˆ์ •์„ฑ์ด ํ•„์ˆ˜์ธ ์ข์€ ๊ฒฝ์šฐ์—๋งŒ ์ •๋‹นํ™”๋˜๊ณ ,
๊ทธ๋งˆ์ €๋„ ๋ณดํ†ต vector<unique_ptr<T>>๋‚˜ std::deque๋กœ ๋” ์ž˜ ํ’€๋ฆฝ๋‹ˆ๋‹ค.
Stroustrup, Sutter, Sean Parent ๋ชจ๋‘ "์˜์‹ฌ์Šค๋Ÿฌ์šฐ๋ฉด vector"๋ฅผ ๊ถŒํ•ฉ๋‹ˆ๋‹ค.

์–ธ๋ฆฌ์–ผ์€ ์ด ์ฒ ํ•™์„ ๋” ๊ฐ•ํ•˜๊ฒŒ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค. TArray๊ฐ€ vector ๋Œ€์‘ 1๊ธ‰ ์‹œ๋ฏผ
์ด๊ณ , std::list ๋Œ€์‘ ์ž๋ฃŒ๊ตฌ์กฐ๋Š” ์˜๋„์ ์œผ๋กœ 1๊ธ‰์œผ๋กœ ๋‘์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.
TLinkedListยทTDoubleLinkedList๊ฐ€ ์žˆ์ง€๋งŒ ํ—ฌํผ ์ˆ˜์ค€์ž…๋‹ˆ๋‹ค. ๊ฒŒ์ž„ ์—”์ง„์€ ๋งค
ํ”„๋ ˆ์ž„ ์ˆ˜๋งŒ ๊ฐ์ฒด๋ฅผ ์ˆœํšŒํ•ด์•ผ ํ•ด์„œ ์บ์‹œ ์นœํ™”์„ฑ์ด ๊ณง ํ”„๋ ˆ์ž„ ์˜ˆ์‚ฐ์ด๊ธฐ
๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ECSยทSoA ํŒจํ„ด๋„ ๊ฐ™์€ ์ด์œ ๋กœ ์ฑ„ํƒ๋ฉ๋‹ˆ๋‹ค.

์š”์•ฝํ•˜๋ฉด, vector๋ฅผ ๊ธฐ๋ณธ์œผ๋กœ ์“ฐ๊ณ , ์ธก์ •ํ•ด์„œ vector๊ฐ€ ๋А๋ฆผ์„ ์ฆ๋ช…ํ•œ ํ›„์—์•ผ
๋‹ค๋ฅธ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ๊ฒ€ํ† ํ•œ๋‹ค โ€” ์ด๊ฒŒ 13๋ฒˆ์˜ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ํ•œ ์ค„์ž…๋‹ˆ๋‹ค.

์ฐธ๊ณ 

  • 11_smart_pointer.md โ€” unique_ptr/shared_ptr์ด ์ปจํ…Œ์ด๋„ˆ ์›์†Œ์ผ ๋•Œ์˜ ํŒจํ„ด (vector<unique_ptr<T>>์ด list ๋Œ€์•ˆ์ธ ์ด์œ )
  • 12_prevent_copy.md โ€” Rule of Five์˜ noexcept ์ด๋™, move-only ํƒ€์ž…(unique_ptr, thread, ifstream)์„ ์ปจํ…Œ์ด๋„ˆ์— ๋‹ด๊ธฐ
  • 09_rtti_raii.md โ€” RAII ์ž์› ๊ด€๋ฆฌ, vector ์ž์ฒด๊ฐ€ RAII ์ •์„ ์‚ฌ๋ก€
  • 10_pointer_deepdive.md โ€” vector ์žฌํ• ๋‹น ํ›„ ๋Œ•๊ธ€๋ง ํฌ์ธํ„ฐ (์บ์‹œ ์นœํ™” vs ์•ˆ์ •์„ฑ ํŠธ๋ ˆ์ด๋“œ์˜คํ”„์˜ ์ •ํ™•ํ•œ ์‚ฌ๋ก€)
  • 00_index.md โ€” CS ๋ฉด์ ‘ ์ธ๋ฑ์Šค (์ด๋ฒˆ 13๋ฒˆ์ด STL+์‹œ์Šคํ…œ ์˜์—ญ ์ง„์ž…์ )
์ด ๊ธฐ์‚ฌ๋Š” ์ €์ž‘๊ถŒ์ž์˜ CC BY 4.0 ๋ผ์ด์„ผ์Šค๋ฅผ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค.

ยฉ GoldBoll. ์ผ๋ถ€ ๊ถŒ๋ฆฌ ๋ณด์œ 

Powered by Jekyll with Chirpy theme

์ธ๊ธฐ ํƒœ๊ทธ