ํฌ์ŠคํŠธ

CS โ€” prevent copy

CS โ€” prevent copy

๐Ÿ“• 04/27 โ€” ๊ฐ์ฒด ๋ณต์‚ฌ ๊ธˆ์ง€ ๋ชจ์˜๋ฉด์ ‘ ์ค€๋น„

๋‚ด์ผ ๋ชจ์˜๋ฉด์ ‘ ์ฃผ์ œ: โ€œ๊ฐ์ฒด ๋ณต์‚ฌ๋ฅผ ๋ง‰๋Š” ๋ฐฉ๋ฒ•์€ ์–ด๋–ค ๋ฐฉ๋ฒ•์ด ์žˆ์„๊นŒ์š”? ์™œ ๊ฐ์ฒด ๋ณต์‚ฌ๋ฅผ ๋ง‰์•„์•ผ ํ• ๊นŒ์š”?โ€ ๋‹จ๋… ์†Œ์œ  ์ž์› โ†’ = delete / private / noncopyable โ†’ Rule of Three/Five/Zero โ†’ move-only(unique_ptr) โ†’ ์Šฌ๋ผ์ด์‹ฑ โ†’ virtual ์†Œ๋ฉธ์ž ๊ผฌ๋ฆฌ์งˆ๋ฌธ ์—ฐ๊ฒฐ ๋‹ค๋ฆฌ


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

๊ฐ์ฒด ๋ณต์‚ฌ๋ฅผ ๋ง‰์•„์•ผ ํ•˜๋Š” ์ด์œ ๋Š” ํฌ๊ฒŒ ๋„ค ๊ฐ€์ง€์ž…๋‹ˆ๋‹ค. ์ฒซ์งธ, ๋‹จ๋… ์†Œ์œ ํ•ด์•ผ ํ•˜๋Š” ์ž์› โ€” ํŒŒ์ผ ํ•ธ๋“ค, ๋ฎคํ…์Šค, ์†Œ์ผ“, unique_ptr์ฒ˜๋Ÿผ ๋‘ ๊ฐ์ฒด๊ฐ€ ๊ฐ™์€ ์ž์›์„ ๋“ค๊ณ  ์žˆ์œผ๋ฉด ์ด์ค‘ ํ•ด์ œ(double free)๋‚˜ ์ž ๊ธˆ ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ๋‘˜์งธ, ๊ณ ๋น„์šฉ ๋ณต์‚ฌ โ€” ํฐ ์ปจํ…Œ์ด๋„ˆ์˜ ๊นŠ์€ ๋ณต์‚ฌ๋Š” ์„ฑ๋Šฅ์„ ํฌ๊ฒŒ ๋–จ์–ด๋œจ๋ฆฝ๋‹ˆ๋‹ค. ์…‹์งธ, ์‹ฑ๊ธ€ํ„ด/๋งค๋‹ˆ์ € ๊ฐ์ฒด์ฒ˜๋Ÿผ ์˜๋„์ ์œผ๋กœ ์ธ์Šคํ„ด์Šค๊ฐ€ 1๊ฐœ์—ฌ์•ผ ํ•  ๋•Œ์ž…๋‹ˆ๋‹ค. ๋„ท์งธ, ๋‹คํ˜• ๊ฐ์ฒด์˜ ์Šฌ๋ผ์ด์‹ฑ(slicing) โ€” Base b = derived; ์ฒ˜๋Ÿผ ๋ณต์‚ฌํ•˜๋ฉด Derived ๋ถ€๋ถ„์ด ์ž˜๋ ค๋‚˜๊ฐ‘๋‹ˆ๋‹ค. ์ž์‹ ๊ฐ์ฒด๋ฅผ ๋ถ€๋ชจ ํƒ€์ž… ๋ณ€์ˆ˜์— ๊ฐ’์œผ๋กœ ๋ณต์‚ฌํ•˜๋ฉด, ์ž์‹์—์„œ ์ถ”๊ฐ€ยท์˜ค๋ฒ„๋ผ์ด๋“œํ•œ ๋ถ€๋ถ„์ด ๋‚ ์•„๊ฐ„๋‹ค

๋ณต์‚ฌ๋ฅผ ๋ง‰๋Š” ๋ฐฉ๋ฒ•์€ C++11 ๊ธฐ์ค€ = delete ๊ฐ€ ํ‘œ์ค€ ๊ถŒ์žฅ ํŒจํ„ด์ž…๋‹ˆ๋‹ค. ๋ณต์‚ฌ ์ƒ์„ฑ์ž์™€ ๋ณต์‚ฌ ๋Œ€์ž… ์—ฐ์‚ฐ์ž์— = delete๋ฅผ ๋ช…์‹œํ•ด ์ปดํŒŒ์ผ ํƒ€์ž„์— ๋ช…ํ™•ํ•œ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๋กœ ์ฐจ๋‹จํ•ฉ๋‹ˆ๋‹ค. C++98 ์ด์ „์—๋Š” private ์„ ์–ธ + ์ •์˜ ์•ˆ ํ•จ ํŒจํ„ด(Boost::noncopyable ์Šคํƒ€์ผ)์„ ์ผ๋Š”๋ฐ, friend ์•ˆ์—์„œ๋Š” ํ˜ธ์ถœ ๊ฐ€๋Šฅํ•˜๊ณ  ๋งํฌ ํƒ€์ž„ ์—๋Ÿฌ๊ฐ€ ๋‚˜์„œ ๋ฉ”์‹œ์ง€๊ฐ€ ๋ชจํ˜ธํ•˜๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ ํ•˜๋‚˜์˜ ํŒจํ„ด์€ move-only ํƒ€์ž…์œผ๋กœ ๋งŒ๋“œ๋Š” ๊ฒƒ โ€” ๋ณต์‚ฌ๋Š” = delete๋กœ ๋ง‰๊ณ  move ์ƒ์„ฑ์ž/๋Œ€์ž…์€ ์‚ด๋ ค๋‘๋ฉด unique_ptr์ฒ˜๋Ÿผ ๋‹จ๋… ์†Œ์œ  + ์†Œ์œ ๊ถŒ ์ด์ „์„ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋•Œ ๋”ฐ๋ผ์˜ค๋Š” ๊ทœ์น™์ด Rule of Three / Five / Zero ์ž…๋‹ˆ๋‹ค. ์†Œ๋ฉธ์žยท๋ณต์‚ฌ ์ƒ์„ฑ์žยท๋ณต์‚ฌ ๋Œ€์ž… ์ค‘ ํ•˜๋‚˜๋ผ๋„ ์ง์ ‘ ์ •์˜ํ•˜๋ฉด ๋‚˜๋จธ์ง€ ๋‘˜๋„ ์ •์˜ํ•ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒŒ Rule of Three์ด๊ณ , C++11๋ถ€ํ„ฐ move ์ƒ์„ฑ์ž/๋Œ€์ž…๊นŒ์ง€ ์ถ”๊ฐ€ํ•ด Rule of Five๊ฐ€ ๋ฉ๋‹ˆ๋‹ค. ๊ฐ€์žฅ ๊ถŒ์žฅ๋˜๋Š” ๊ฑด Rule of Zero โ€” RAII ํƒ€์ž…(unique_ptr, vector ๋“ฑ)์— ์ž์› ๊ด€๋ฆฌ๋ฅผ ์œ„์ž„ํ•˜๊ณ  ์‚ฌ์šฉ์ž๋Š” ํŠน๋ณ„ ๋ฉค๋ฒ„ ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์–ด์ œ ์ •๋ฆฌํ•œ ์Šค๋งˆํŠธ ํฌ์ธํ„ฐ์˜ unique_ptr์ด ์ •ํ™•ํžˆ ๋ณต์‚ฌ = delete + move only ํŒจํ„ด์ด๋ฉฐ, shared_ptr์€ ๋ณต์‚ฌ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ ์ฐธ์กฐ ์นด์šดํŒ…์œผ๋กœ ๊ณต์œ  ์†Œ์œ ๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ํ‘œํ˜„ํ•ฉ๋‹ˆ๋‹ค.

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

  • ๊ฐ์ฒด ๋ณต์‚ฌ (Copy) โ€” ๋ณต์‚ฌ ์ƒ์„ฑ์ž(T(const T&))์™€ ๋ณต์‚ฌ ๋Œ€์ž… ์—ฐ์‚ฐ์ž(operator=(const T&))๋กœ ๋™์ผ ํƒ€์ž… ๊ฐ์ฒด๋ฅผ ์ƒˆ๋กœ ๋งŒ๋“ค๊ฑฐ๋‚˜ ๋ฎ์–ด์“ฐ๋Š” ๋™์ž‘
  • = delete (C++11) โ€” ํŠน๋ณ„ ๋ฉค๋ฒ„ ํ•จ์ˆ˜๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ์‚ญ์ œ. ์ปดํŒŒ์ผ ํƒ€์ž„์— ๋ช…ํ™•ํ•œ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ ์ œ๊ณต โ€” ๋ณต์‚ฌ ์ฐจ๋‹จ์˜ ๋ชจ๋˜ ํ‘œ์ค€ ํŒจํ„ด
  • private ์„ ์–ธ + ์ •์˜ ์•ˆ ํ•จ (C++98) โ€” Boost::noncopyable ํŒจํ„ด. friend ์šฐํšŒ ๊ฐ€๋Šฅ, ๋งํฌ ์—๋Ÿฌ๋กœ ๋ฉ”์‹œ์ง€ ๋ชจํ˜ธ โ€” ๋ ˆ๊ฑฐ์‹œ ์ฝ”๋“œ์—์„œ๋งŒ ๋“ฑ์žฅ
  • noncopyable ๋ฒ ์ด์Šค ํด๋ž˜์Šค โ€” ๋ณต์‚ฌ ์ฐจ๋‹จ์„ ์บก์Аํ™”ํ•œ ๊ธฐ๋ฐ˜ ํด๋ž˜์Šค ์ƒ์†(์˜ˆ: boost::noncopyable, FNoncopyable)
  • move-only ํƒ€์ž… โ€” ๋ณต์‚ฌ๋Š” delete, move๋Š” ํ—ˆ์šฉ โ€” unique_ptr, thread, lock_guard๊ฐ€ ๋Œ€ํ‘œ ์‚ฌ๋ก€
  • ์†Œ์œ ๊ถŒ(Ownership) โ€” ์ž์›์„ ๋ˆ„๊ฐ€ ์ฑ…์ž„์ง€๊ณ  ํ•ด์ œํ•  ๊ฒƒ์ธ๊ฐ€์˜ ์˜๋ฏธ๋ก . ๋‹จ๋…/๊ณต์œ /๊ด€์ฐฐ๋กœ ๊ตฌ๋ถ„
  • ์ด์ค‘ ํ•ด์ œ (Double Free) โ€” ๊ฐ™์€ ์ž์›์„ ๋‘ ๋ฒˆ delete ํ•˜๋Š” ๋ฏธ์ •์˜ ๋™์ž‘. ๋ณต์‚ฌ ํ—ˆ์šฉ + ์†Œ๋ฉธ์ž์—์„œ ํ•ด์ œํ•˜๋ฉด ๋ฐœ์ƒ
  • ๊ฐ์ฒด ์Šฌ๋ผ์ด์‹ฑ (Object Slicing) โ€” Base b = derived; ์‹œ Derived ๋ถ€๋ถ„์ด ์ž˜๋ ค๋‚˜๊ฐ€ ๋ฐ์ดํ„ฐ ์†์‹ค + vptr์ด Base๋กœ ๊ณ ์ •๋˜๋Š” ํ˜„์ƒ
  • Rule of Three โ€” ์†Œ๋ฉธ์žยท๋ณต์‚ฌ ์ƒ์„ฑ์žยท๋ณต์‚ฌ ๋Œ€์ž… ์—ฐ์‚ฐ์ž๊ฐ€ ํ•œ ์„ธํŠธ. ํ•˜๋‚˜ ์ •์˜ํ•˜๋ฉด ์…‹ ๋‹ค ์ •์˜ (C++98)
  • Rule of Five โ€” Rule of Three + move ์ƒ์„ฑ์ž + move ๋Œ€์ž… ์—ฐ์‚ฐ์ž (C++11)
  • Rule of Zero โ€” ์ž์› ๊ด€๋ฆฌ๋Š” RAII ํƒ€์ž…์— ์œ„์ž„ํ•˜๊ณ  ์‚ฌ์šฉ์ž๋Š” ํŠน๋ณ„ ๋ฉค๋ฒ„ ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•˜์ง€ ์•Š๋Š” ๊ถŒ์žฅ ๊ด€์šฉ๊ตฌ
  • ํŠน๋ณ„ ๋ฉค๋ฒ„ ํ•จ์ˆ˜ (Special Member Functions) โ€” ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์ž๋™ ์ƒ์„ฑํ•˜๋Š” 6์ข…: ๊ธฐ๋ณธ/๋ณต์‚ฌ/์ด๋™ ์ƒ์„ฑ์ž, ๋ณต์‚ฌ/์ด๋™ ๋Œ€์ž… ์—ฐ์‚ฐ์ž, ์†Œ๋ฉธ์ž
  • ์•”๋ฌต์  ์‚ญ์ œ (Implicit Deletion) โ€” ๋ฉค๋ฒ„ ์ค‘ ํ•˜๋‚˜๊ฐ€ ๋ณต์‚ฌ ๋ถˆ๊ฐ€๋Šฅํ•˜๋ฉด ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ํด๋ž˜์Šค์˜ ๋ณต์‚ฌ ์—ฐ์‚ฐ์„ ์ž๋™ delete ์ฒ˜๋ฆฌ
  • ์‹ฑ๊ธ€ํ„ด (Singleton) โ€” ์ธ์Šคํ„ด์Šค๊ฐ€ ์ •ํ™•ํžˆ 1๊ฐœ์—ฌ์•ผ ํ•˜๋Š” ๊ฐ์ฒด. ๋ณต์‚ฌยท์ด๋™ ๋ชจ๋‘ ์ฐจ๋‹จํ•ด ์˜๋„ ํ‘œํ˜„
  • UE_NONCOPYABLE / FNoncopyable โ€” ์–ธ๋ฆฌ์–ผ์ด ์ œ๊ณตํ•˜๋Š” ๋ณต์‚ฌ ์ฐจ๋‹จ ๋งคํฌ๋กœ/๋ฒ ์ด์Šค. ํ•œ ์ค„๋กœ Rule of Five์˜ ๋ณต์‚ฌ ๋ถ€๋ถ„ ์ฒ˜๋ฆฌ
  • ํŒŒ์ผ ํ•ธ๋“ค (File Handle) โ€” OS๊ฐ€ ๊ด€๋ฆฌํ•˜๋Š” ์ปค๋„ ๊ฐ์ฒด์— ๋Œ€ํ•œ ์‚ฌ์šฉ์ž ๊ณต๊ฐ„ ์‹๋ณ„์ž(FILE*, POSIX fd, Windows HANDLE). ๋ณต์‚ฌ ์‹œ ๊ฐ™์€ ํ•ธ๋“ค์„ ๊ฐ€๋ฆฌ์ผœ ์ด์ค‘ close ์œ„ํ—˜
  • ์ด์ค‘ close (Double Close) โ€” ๊ฐ™์€ fd/HANDLE์„ ๋‘ ๋ฒˆ ๋‹ซ๋Š” ๋™์ž‘. ์‚ฌ์ด์— ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๊ฐ€ ์ƒˆ fd๋ฅผ ๊ฐ™์€ ๋ฒˆํ˜ธ๋กœ ๋ฐ›์œผ๋ฉด ์—‰๋šฑํ•œ ์ž์› ๋‹ซํž˜ โ†’ fd ์žฌ์‚ฌ์šฉ ๊ณต๊ฒฉ
  • std::fstream ์ด๋™ ์ „์šฉ ์„ค๊ณ„ (C++11) โ€” ifstream/ofstream/fstream์ด C++11์—์„œ ๋ณต์‚ฌ = delete, move๋งŒ ํ—ˆ์šฉ. RAII๋กœ ๋‹ซํž˜ ๋ณด์žฅ
  • ๋ฎคํ…์Šค (Mutex) โ€” ์ž„๊ณ„ ์˜์—ญ ๋ณดํ˜ธ์šฉ ๋™๊ธฐํ™” ๊ฐ์ฒด. std::mutex๋Š” ๋ณต์‚ฌยท์ด๋™ ๋ชจ๋‘ = delete (์ž ๊ธˆ ์ƒํƒœ ์˜๋ฏธ๊ฐ€ ๋ชจํ˜ธ)
  • ์ž ๊ธˆ ์ƒํƒœ ์˜๋ฏธ ๋ชจํ˜ธ์„ฑ โ€” ๋ฎคํ…์Šค ๋ณต์‚ฌ ์‹œ โ€œ์ž ๊ธด ์ฑ„๋กœ ๋ณต์‚ฌ๋˜๋‚˜? ํ’€๋ฆฐ ์ƒํƒœ๋กœ?โ€ ๋‹ต์ด ์—†์Œ โ†’ ํ‘œ์ค€์€ ๋ณต์‚ฌยท์ด๋™ ๋ชจ๋‘ ์ฐจ๋‹จ
  • std::lock_guard (move ๋ถˆ๊ฐ€) โ€” ๋ณต์‚ฌยท์ด๋™ ๋ชจ๋‘ = delete. ์Šค์ฝ”ํ”„ RAII์— ๊ฐ€์žฅ ๊ฐ€๋ฒผ์›€
  • std::unique_lock (move ๊ฐ€๋Šฅ) โ€” ๋ณต์‚ฌ = delete, move ํ—ˆ์šฉ. ์ž ๊ธˆ ์†Œ์œ ๊ถŒ์„ ํ•จ์ˆ˜ ๊ฐ„ ์ด์ „ ๊ฐ€๋Šฅ โ€” ์กฐ๊ฑด ๋ณ€์ˆ˜์™€ ํ•จ๊ป˜ ์“ธ ๋•Œ ํ•„์ˆ˜
  • std::scoped_lock (C++17) โ€” ๋ณต์ˆ˜ ๋ฎคํ…์Šค๋ฅผ ๋ฐ๋“œ๋ฝ ์—†์ด ์ž ๊ทธ๋Š” RAII. ์—ญ์‹œ ๋ณต์‚ฌยท์ด๋™ ์ฐจ๋‹จ
  • ์†Œ์ผ“ ๋””์Šคํฌ๋ฆฝํ„ฐ (Socket Descriptor) โ€” POSIX int, Winsock SOCKET. fd์˜ ์ผ์ข…์ด๋ฉฐ ๋™์ผํ•˜๊ฒŒ ์ด์ค‘ closeยท์—ฐ๊ฒฐ ์ƒํƒœ ๊ณต์œ  ๋ฌธ์ œ
  • boost::asio::ip::tcp::socket / asio::socket โ€” ๋ณต์‚ฌ = delete, move๋งŒ ํ—ˆ์šฉ. ๋น„๋™๊ธฐ ํ•ธ๋“ค๋Ÿฌ ์ฒด์ธ์—์„œ ์†Œ์œ ๊ถŒ ์ด์ „์„ ์œ„ํ•ด move-only ์„ค๊ณ„
  • ์—ฐ๊ฒฐ ์ƒํƒœ ๊ณต์œ  ๋ฌธ์ œ โ€” ๊ฐ™์€ ์†Œ์ผ“์„ ๋‘ ๊ฐ์ฒด๊ฐ€ ๋“ค๋ฉด ํ•œ์ชฝ์ด send ์ค‘์ผ ๋•Œ ๋‹ค๋ฅธ ์ชฝ์ด close โ†’ ๋ถ€๋ถ„ ์†ก์‹ /RST ๋ฐœ์ƒ, TCP ์ƒํƒœ ๋จธ์‹  ์˜ค์—ผ

๋ชฉ์ฐจ

  1. ํ•ต์‹ฌ ์š”์•ฝ ์นด๋“œ
  2. ์™œ ๋ณต์‚ฌ๋ฅผ ๋ง‰์•„์•ผ ํ•˜๋Š”๊ฐ€
  3. ์–ด๋–ป๊ฒŒ ๋ณต์‚ฌ๋ฅผ ๋ง‰๋Š”๊ฐ€
  4. Rule of Three / Five / Zero
  5. move-only ํƒ€์ž… โ€” unique_ptr ํŒจํ„ด
  6. ๋‹จ๋… ์†Œ์œ  ์ž์› ์‹ฌํ™” โ€” ํŒŒ์ผ ํ•ธ๋“ค / ๋ฎคํ…์Šค / ์†Œ์ผ“
  7. ๊ฐ์ฒด ์Šฌ๋ผ์ด์‹ฑ ๋ฐฉ์ง€
  8. ๊ผฌ๋ฆฌ์งˆ๋ฌธ ์˜ˆ์ƒ ๊ฒฝ๋กœ
  9. ์–ธ๋ฆฌ์–ผ์—์„œ์˜ ๋ณต์‚ฌ ๊ธˆ์ง€

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

์™œ ๋ง‰๋Š”๊ฐ€ 30์ดˆ

1
2
3
4
5
1) ๋‹จ๋… ์†Œ์œ  ์ž์› โ€” ํŒŒ์ผ/๋ฎคํ…์Šค/์†Œ์ผ“/unique_ptr
   ๋ณต์‚ฌํ•˜๋ฉด ์ด์ค‘ ํ•ด์ œ, ์ž ๊ธˆ ์ถฉ๋Œ
2) ๊ณ ๋น„์šฉ ๋ณต์‚ฌ โ€” ํฐ ์ปจํ…Œ์ด๋„ˆ ๊นŠ์€ ๋ณต์‚ฌ
3) ์‹ฑ๊ธ€ํ„ด/๋งค๋‹ˆ์ € โ€” ์ธ์Šคํ„ด์Šค 1๊ฐœ๊ฐ€ ๋ณธ์งˆ
4) ์Šฌ๋ผ์ด์‹ฑ โ€” Base b = derived ์‹œ Derived ๋ถ€๋ถ„ ์†์‹ค

์–ด๋–ป๊ฒŒ ๋ง‰๋Š”๊ฐ€ 30์ดˆ

1
2
3
4
5
C++11+ ํ‘œ์ค€:  ๋ณต์‚ฌ ์ƒ์„ฑ์ž/๋Œ€์ž…์— = delete
C++98 ํŒจํ„ด:   private ์„ ์–ธ + ์ •์˜ X (Boost::noncopyable)
๋ฒ ์ด์Šค ์ƒ์†:  class X : private Noncopyable {}
move-only:    ๋ณต์‚ฌ delete + move ํ—ˆ์šฉ (unique_ptr ์Šคํƒ€์ผ)
์ธ์Šคํ„ด์Šค ์ฐจ๋‹จ: ์ƒ์„ฑ์ž/์†Œ๋ฉธ์ž protected (์‹ฑ๊ธ€ํ„ด)

Rule of N 30์ดˆ

1
2
3
Rule of Three  โ€” ์†Œ๋ฉธ์ž/๋ณต์‚ฌ ์ƒ์„ฑ์ž/๋ณต์‚ฌ ๋Œ€์ž… ์ค‘ ํ•˜๋‚˜ ์ •์˜ โ†’ ์…‹ ๋‹ค ์ •์˜
Rule of Five   โ€” + move ์ƒ์„ฑ์ž + move ๋Œ€์ž… (C++11)
Rule of Zero   โ€” RAII ํƒ€์ž…์— ์œ„์ž„. ํŠน๋ณ„ ๋ฉค๋ฒ„ ํ•จ์ˆ˜ ์ •์˜ ์•ˆ ํ•จ (๊ถŒ์žฅ)

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
๋ณต์‚ฌ๋ฅผ ๋ง‰๋Š” ๋ฐฉ๋ฒ•
โ”œโ”€โ”€ = delete (C++11 ํ‘œ์ค€)
โ”‚   โ”œโ”€โ”€ ์ปดํŒŒ์ผ ํƒ€์ž„ ๋ช…ํ™•ํ•œ ์—๋Ÿฌ
โ”‚   โ””โ”€โ”€ private ํŒจํ„ด ๋Œ€๋น„ friend ์šฐํšŒ ๋ถˆ๊ฐ€
โ”œโ”€โ”€ private + ์ •์˜ X (C++98)
โ”‚   โ”œโ”€โ”€ ๋งํฌ ํƒ€์ž„ ์—๋Ÿฌ โ†’ ๋ฉ”์‹œ์ง€ ๋ชจํ˜ธ
โ”‚   โ””โ”€โ”€ friend ์•ˆ์—์„œ๋Š” ํ˜ธ์ถœ ๊ฐ€๋Šฅ (๊ตฌ๋ฉ)
โ”œโ”€โ”€ noncopyable ๋ฒ ์ด์Šค ์ƒ์†
โ”‚   โ”œโ”€โ”€ Boost::noncopyable
โ”‚   โ””โ”€โ”€ UE_NONCOPYABLE / FNoncopyable
โ”œโ”€โ”€ move-only ํƒ€์ž… (โ˜… 11๋ฒˆ unique_ptr ์—ฐ๊ฒฐ)
โ”‚   โ”œโ”€โ”€ ๋ณต์‚ฌ delete + move ํ—ˆ์šฉ
โ”‚   โ””โ”€โ”€ std::move๋กœ ์†Œ์œ ๊ถŒ ์ด์ „
โ”œโ”€โ”€ ๋‹จ๋… ์†Œ์œ  ์ž์› ์‹ฌํ™” (โ˜… 6์žฅ)
โ”‚   โ”œโ”€โ”€ ํŒŒ์ผ ํ•ธ๋“ค โ€” fstream move-only, ์ด์ค‘ close, fd ์žฌ์‚ฌ์šฉ ๊ณต๊ฒฉ
โ”‚   โ”œโ”€โ”€ ๋ฎคํ…์Šค โ€” ๋ณต์‚ฌยท์ด๋™ ๋‘˜ ๋‹ค delete, lock_guard/unique_lock/scoped_lock
โ”‚   โ””โ”€โ”€ ์†Œ์ผ“ โ€” Asio socket move-only, ์—ฐ๊ฒฐ ์ƒํƒœ ๊ณต์œ  ๋ฌธ์ œ
โ”œโ”€โ”€ Rule of Three / Five / Zero
โ”‚   โ””โ”€โ”€ ์ž์› ๊ด€๋ฆฌ โ†’ RAII ์œ„์ž„ ๊ถŒ์žฅ
โ””โ”€โ”€ ์Šฌ๋ผ์ด์‹ฑ ๋ฐฉ์ง€ (โ˜… 06๋ฒˆ virtual ์†Œ๋ฉธ์ž ์—ฐ๊ฒฐ)
    โ””โ”€โ”€ ๋‹คํ˜• ๊ธฐ๋ฐ˜ ํด๋ž˜์Šค โ†’ noncopyable + virtual ์†Œ๋ฉธ์ž

2. ์™œ ๋ณต์‚ฌ๋ฅผ ๋ง‰์•„์•ผ ํ•˜๋Š”๊ฐ€

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

โ€œ๊ฐ™์€ ์ž์›์„ ๋‘ ๊ฐ์ฒด๊ฐ€ ๋“ค๋ฉด ์˜๋ฏธ๊ฐ€ ๊นจ์ง€๊ฑฐ๋‚˜ ์ž์› ๊ด€๋ฆฌ๊ฐ€ ๋ฌด๋„ˆ์ง€๋Š” ๊ฒฝ์šฐโ€ ์— ๋ณต์‚ฌ๋ฅผ ๋ง‰์Šต๋‹ˆ๋‹ค. ๋ณต์‚ฌ ๊ฐ€๋Šฅํ•œ์ง€ ์—ฌ๋ถ€๋Š” ๋‹จ์ˆœ ํŽธ์˜๊ฐ€ ์•„๋‹ˆ๋ผ ํƒ€์ž…์˜ ์˜๋ฏธ๋ก (semantics) ์˜ ์ผ๋ถ€์ž…๋‹ˆ๋‹ค.

์ด์œ  1 โ€” ๋‹จ๋… ์†Œ์œ  ์ž์›์˜ ์˜๋ฏธ ๊นจ์ง

๊ฐ€์žฅ ํ”ํ•˜๊ณ  ์ค‘์š”ํ•œ ์ด์œ ์ž…๋‹ˆ๋‹ค. ์ž์›์€ ์ฑ…์ž„์ž๊ฐ€ ์ •ํ™•ํžˆ ํ•œ ๋ช…์ด์–ด์•ผ ์•ˆ์ „ํ•œ ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Šต๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
class FileHandle {
    FILE* fp;
public:
    FileHandle(const char* path) : fp(fopen(path, "r")) {}
    ~FileHandle() { if (fp) fclose(fp); }   // ์†Œ๋ฉธ ์‹œ ๋‹ซ์Œ
};

FileHandle a("data.txt");
FileHandle b = a;   // โŒ ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์ž๋™ ์ƒ์„ฑํ•œ ๋ณต์‚ฌ โ€” fp ํฌ์ธํ„ฐ๋งŒ ๋ณต์‚ฌ
                    //    a.fp == b.fp (์–•์€ ๋ณต์‚ฌ)
// ์Šค์ฝ”ํ”„ ์ข…๋ฃŒ ์‹œ:
//   b ์†Œ๋ฉธ โ†’ fclose(fp)
//   a ์†Œ๋ฉธ โ†’ fclose(fp)  โ† ๊ฐ™์€ fp ๋‘ ๋ฒˆ ๋‹ซ์Œ! ๋ฏธ์ •์˜ ๋™์ž‘

๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ์ž์›:

  • ํŒŒ์ผ ํ•ธ๋“ค โ€” ์ด์ค‘ fclose โ†’ UB
  • ๋ฎคํ…์Šค โ€” lock_guard ๋ณต์‚ฌํ•˜๋ฉด ๊ฐ™์€ mutex๊ฐ€ ๋‘ ๋ฒˆ unlock โ†’ UB
  • ์†Œ์ผ“ โ€” ๊ฐ™์€ fd๋ฅผ ๋‘ ๋ฒˆ close
  • unique_ptr โ€” ๊ฐ™์€ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋‘ ๋ฒˆ delete โ†’ ํž™ ์†์ƒ
  • DB ์ปค๋„ฅ์…˜, ํ•ธ๋“ค โ€” ์ž์› ๊ด€๋ฆฌ์ž๊ฐ€ ์ถ”์  ๋ชป ํ•จ

์ด์œ  2 โ€” ๊ณ ๋น„์šฉ ๋ณต์‚ฌ

์ž์›์€ 1๊ฐœ๋ผ๋„ ๋ฐ์ดํ„ฐ๊ฐ€ ๊ฑฐ๋Œ€ํ•˜๋ฉด ์˜๋„์น˜ ์•Š์€ ๋ณต์‚ฌ๋ฅผ ๋ง‰์•„ ์„ฑ๋Šฅ์„ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
8
9
10
class HugeMatrix {
    std::vector<std::vector<double>> data;  // ์ˆ˜์‹ญ MB
public:
    // ๋ณต์‚ฌ๋ฅผ ํ—ˆ์šฉํ•˜๋ฉด ํ•จ์ˆ˜ ์ธ์ž ํŒจ์Šค์—์„œ ์˜๋„์น˜ ์•Š๊ฒŒ ๋ฉ”๊ฐ€๋ฐ”์ดํŠธ ๋ณต์‚ฌ ๋ฐœ์ƒ
    HugeMatrix(const HugeMatrix&) = delete;
    HugeMatrix(HugeMatrix&&) = default;     // move๋Š” ์‚ด๋ฆผ
};

void Process(HugeMatrix m);   // โ† ์ด ์‹œ์ ์— ์ปดํŒŒ์ผ ์—๋Ÿฌ๋กœ ์‚ฌ์šฉ์ž์—๊ฒŒ ๊ฒฝ๊ณ 
                              //    Process(std::move(m)) ์œผ๋กœ๋งŒ ํ˜ธ์ถœ ๊ฐ€๋Šฅ

์ด์œ  3 โ€” ์‹ฑ๊ธ€ํ„ด / ๋งค๋‹ˆ์ € ๊ฐ์ฒด

์ธ์Šคํ„ด์Šค๊ฐ€ 1๊ฐœ์ž„์„ ํƒ€์ž… ์ž์ฒด๋กœ ๊ฐ•์ œํ•ฉ๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class GameManager {
public:
    static GameManager& Instance() {
        static GameManager s;
        return s;
    }
private:
    GameManager() = default;
    ~GameManager() = default;
    GameManager(const GameManager&) = delete;
    GameManager& operator=(const GameManager&) = delete;
    // move๋„ ๋ณดํ†ต ํ•จ๊ป˜ ๋ง‰์Œ
    GameManager(GameManager&&) = delete;
    GameManager& operator=(GameManager&&) = delete;
};

์ด์œ  4 โ€” ๊ฐ์ฒด ์Šฌ๋ผ์ด์‹ฑ(Slicing)

๋‹คํ˜• ๊ฐ์ฒด๋ฅผ ๊ฐ’์œผ๋กœ ๋ณต์‚ฌํ•˜๋ฉด ํŒŒ์ƒ ํด๋ž˜์Šค(Derived = Base๋ฅผ ์ƒ์†ํ•œ ์ž์‹ ํด๋ž˜์Šค, ์•„๋ž˜ ์˜ˆ์‹œ์˜ Circle)์—์„œ ์ƒˆ๋กœ ์ถ”๊ฐ€ํ•œ ๋ฉค๋ฒ„ยท์˜ค๋ฒ„๋ผ์ด๋“œ ์ •๋ณด๊ฐ€ ํ†ต์งธ๋กœ ์ž˜๋ ค๋‚˜๊ฐ‘๋‹ˆ๋‹ค.

์šฉ์–ด ์ •๋ฆฌ

  • Base(๊ธฐ๋ฐ˜ ํด๋ž˜์Šค): ์ƒ์†์˜ ๋ถ€๋ชจ. ์˜ˆ์‹œ์˜ Shape.
  • Derived(ํŒŒ์ƒ ํด๋ž˜์Šค): Base๋ฅผ ์ƒ์†ํ•ด ๋ฉค๋ฒ„๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ๊ฐ€์ƒ ํ•จ์ˆ˜๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋“œํ•œ ์ž์‹. ์˜ˆ์‹œ์˜ Circle.
  • ์ž˜๋ ค๋‚˜๊ฐ€๋Š” ๋ถ€๋ถ„: Derived๊ฐ€ Base ์œ„์— ๋ง๋ถ™์ธ ์ถ”๊ฐ€ ๋ฉค๋ฒ„(Circle::r)์™€ ๊ฐ€์ƒ ํ•จ์ˆ˜ ๋””์ŠคํŒจ์น˜ ์ •๋ณด(vptr โ†’ Circle::Area).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Shape {
public:
    virtual double Area() const { return 0; }
};

class Circle : public Shape {
    double r;
public:
    Circle(double r) : r(r) {}
    double Area() const override { return 3.14 * r * r; }
};

Circle c(5);
Shape s = c;   // โŒ ์Šฌ๋ผ์ด์‹ฑ! Circle::r ์ž˜๋ ค๋‚˜๊ฐ, vptr๋„ Shape๋กœ ๊ณ ์ •
s.Area();      // 0 ๋ฐ˜ํ™˜ (Circle::Area ํ˜ธ์ถœ ์•ˆ ๋จ)

๋‹คํ˜• ํด๋ž˜์Šค๋Š” ๋ณดํ†ต ์ถ”์ƒ ํด๋ž˜์Šค๋กœ ๋งŒ๋“ค๊ฑฐ๋‚˜(์ˆœ์ˆ˜ ๊ฐ€์ƒ), ๋ณต์‚ฌ ์ž์ฒด๋ฅผ ๋ง‰์•„ ์Šฌ๋ผ์ด์‹ฑ์„ ์ฐจ๋‹จํ•ฉ๋‹ˆ๋‹ค โ†’ 06_virtual_destructor.md ์—ฐ๊ฒฐ ๋‹ค๋ฆฌ.

์˜๋ฏธ๋ก  ์ •๋ฆฌํ‘œ

์ž์› ์ข…๋ฅ˜๋ณต์‚ฌ ์˜๋ฏธ๊ถŒ์žฅ ์ฒ˜๋ฆฌ
ํŒŒ์ผ/์†Œ์ผ“/๋ฎคํ…์Šค์ด์ค‘ ํ•ด์ œยท์ž ๊ธˆ ์ถฉ๋Œ= delete (move-only)
unique_ptr๋‹จ๋… ์†Œ์œ  ๊นจ์ง= delete (move-only)
shared_ptr๊ณต์œ  ์†Œ์œ  โ€” ์นด์šดํŠธ ์ฆ๊ฐ€๋ณต์‚ฌ ํ—ˆ์šฉ
ํฐ ๋ฐ์ดํ„ฐ(POD)๊นŠ์€ ๋ณต์‚ฌ ๋น„์šฉ๋ณดํ†ต ํ—ˆ์šฉ + ์˜๋„์  ๋ง‰๊ธฐ
์‹ฑ๊ธ€ํ„ด/๋งค๋‹ˆ์ €์ธ์Šคํ„ด์Šค ์ค‘๋ณต= delete ๋ณต์‚ฌ+์ด๋™
๋‹คํ˜• ๊ธฐ๋ฐ˜ ํด๋ž˜์Šค์Šฌ๋ผ์ด์‹ฑ ์œ„ํ—˜= delete ๋˜๋Š” ์ถ”์ƒํ™”

3. ์–ด๋–ป๊ฒŒ ๋ณต์‚ฌ๋ฅผ ๋ง‰๋Š”๊ฐ€

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

C++11๋ถ€ํ„ฐ = delete๊ฐ€ ํ‘œ์ค€ ๊ถŒ์žฅ ํŒจํ„ด์ž…๋‹ˆ๋‹ค. C++98 ์‹œ์ ˆ์˜ private ํŠธ๋ฆญ์€ ๋” ์ด์ƒ ์“ธ ์ด์œ ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

๋ฐฉ๋ฒ• 1 โ€” = delete (C++11, ๋ชจ๋˜ ๊ถŒ์žฅ)

1
2
3
4
5
6
7
8
9
10
11
class NoCopy {
public:
    NoCopy() = default;
    NoCopy(const NoCopy&) = delete;             // ๋ณต์‚ฌ ์ƒ์„ฑ์ž ์‚ญ์ œ
    NoCopy& operator=(const NoCopy&) = delete;  // ๋ณต์‚ฌ ๋Œ€์ž… ์‚ญ์ œ
};

NoCopy a;
NoCopy b = a;    // โŒ error: call to deleted constructor of 'NoCopy'
NoCopy c;
c = a;           // โŒ error: overload resolution selected deleted operator '='

์žฅ์ :

  • ์ปดํŒŒ์ผ ํƒ€์ž„ ๋ช…ํ™•ํ•œ ์—๋Ÿฌ โ€” deleted function ๋ฉ”์‹œ์ง€๊ฐ€ ์ฆ‰์‹œ ๋‚˜์˜ด
  • friend ์•ˆ์—์„œ๋„ ํ˜ธ์ถœ ๋ถˆ๊ฐ€ โ€” private ํŠธ๋ฆญ์˜ ๊ตฌ๋ฉ์„ ๋ง‰์Œ
  • ์˜๋„๊ฐ€ ์ฝ”๋“œ์— ๋ช…์‹œ์  โ€” public ์˜์—ญ์—์„œ delete๋กœ ์„ ์–ธํ•˜๋Š” ๊ฒŒ ๊ฐ€๋…์„ฑ ์ข‹์Œ

๋ฐฉ๋ฒ• 2 โ€” private ์„ ์–ธ + ์ •์˜ ์•ˆ ํ•จ (C++98 ํŒจํ„ด)

1
2
3
4
5
6
7
class NoCopy {
public:
    NoCopy() {}
private:
    NoCopy(const NoCopy&);              // ์„ ์–ธ๋งŒ, ์ •์˜ ์—†์Œ
    NoCopy& operator=(const NoCopy&);   // ์„ ์–ธ๋งŒ, ์ •์˜ ์—†์Œ
};

๋‹จ์ :

  • friend ํ•จ์ˆ˜/๋ฉค๋ฒ„ ํ•จ์ˆ˜ ์•ˆ์—์„œ๋Š” ํ˜ธ์ถœ ๊ฐ€๋Šฅ โ†’ ๋งํฌ ํƒ€์ž„์—์•ผ ์—๋Ÿฌ
  • ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๊ฐ€ ๋ชจํ˜ธ โ€” undefined reference to NoCopy::NoCopy(NoCopy const&)
  • C++11 ์ดํ›„ ์‚ฌ์šฉ ์ด์œ  ์—†์Œ โ€” = delete๋กœ ๊ต์ฒดํ•ด์•ผ ํ•จ

๋ฐฉ๋ฒ• 3 โ€” noncopyable ๋ฒ ์ด์Šค ํด๋ž˜์Šค ์ƒ์†

Boost::noncopyable ์Šคํƒ€์ผ๋กœ ๋ณต์‚ฌ ์ฐจ๋‹จ์„ ์บก์Аํ™”ํ•œ ๋ฒ ์ด์Šค๋ฅผ ์ƒ์†ํ•ฉ๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
class Noncopyable {
protected:
    Noncopyable() = default;
    ~Noncopyable() = default;
public:
    Noncopyable(const Noncopyable&) = delete;
    Noncopyable& operator=(const Noncopyable&) = delete;
};

class Database : private Noncopyable {
    // ์ž๋™์œผ๋กœ ๋ณต์‚ฌ ๋ถˆ๊ฐ€
};

์žฅ์ : ํด๋ž˜์Šค๋งˆ๋‹ค ๋‘ ์ค„์”ฉ ์“ฐ์ง€ ์•Š์•„๋„ ๋จ, ์˜๋„ ๋ช…ํ™• ๋‹จ์ : ๋‹จ์ผ ์ƒ์† ์Šฌ๋กฏ ์ฐจ์ง€(๋ณดํ†ต private ์ƒ์†์ด๋ผ ํฐ ๋ฌธ์ œ๋Š” ์•„๋‹˜), EBO๋กœ ํฌ๊ธฐ ์ฆ๊ฐ€๋Š” ์—†์Œ

๋ฐฉ๋ฒ• 4 โ€” move-only ํƒ€์ž…

๋ณต์‚ฌ๋Š” = delete, move๋Š” ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค โ€” 11๋ฒˆ unique_ptr ํŒจํ„ด๊ณผ ๋™์ผ.

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
class FileHandle {
    FILE* fp = nullptr;
public:
    explicit FileHandle(const char* path) : fp(fopen(path, "r")) {}
    ~FileHandle() { if (fp) fclose(fp); }

    // ๋ณต์‚ฌ ๊ธˆ์ง€
    FileHandle(const FileHandle&) = delete;
    FileHandle& operator=(const FileHandle&) = delete;

    // move ํ—ˆ์šฉ โ€” ์†Œ์œ ๊ถŒ ์ด์ „
    FileHandle(FileHandle&& o) noexcept : fp(o.fp) { o.fp = nullptr; }
    FileHandle& operator=(FileHandle&& o) noexcept {
        if (this != &o) {
            if (fp) fclose(fp);
            fp = o.fp;
            o.fp = nullptr;
        }
        return *this;
    }
};

FileHandle a("data.txt");
FileHandle b = std::move(a);   // โœ… ์†Œ์œ ๊ถŒ ์ด์ „. a.fp == nullptr
// ์ด์ค‘ fclose ์—†์Œ โ€” a ์†Œ๋ฉธ์ž๊ฐ€ nullptr ์ฒดํฌ

์ด๊ฒŒ ์ •ํ™•ํžˆ std::unique_ptr์ด ๊ตฌํ˜„๋œ ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค โ†’ 11๋ฒˆ [์Šค๋งˆํŠธ ํฌ์ธํ„ฐ] ์—ฐ๊ฒฐ ๋‹ค๋ฆฌ.

๋ฐฉ๋ฒ• 5 โ€” ์ƒ์„ฑ์ž/์†Œ๋ฉธ์ž protected (์ธ์Šคํ„ด์Šคํ™” ์ž์ฒด ์ œ์–ด)

์‹ฑ๊ธ€ํ„ด์ด๋‚˜ ํŒฉํ† ๋ฆฌ ์ „์šฉ ๊ฐ์ฒด๋Š” ์™ธ๋ถ€์—์„œ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์—†๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
class Logger {
public:
    static Logger& Instance() {
        static Logger l;
        return l;
    }
    Logger(const Logger&) = delete;
    Logger& operator=(const Logger&) = delete;
protected:
    Logger() = default;     // ์™ธ๋ถ€์—์„œ ์ง์ ‘ ์ƒ์„ฑ ๋ถˆ๊ฐ€
    ~Logger() = default;
};

๋น„๊ต ํ‘œ

๋ฐฉ๋ฒ•์‹œ๊ธฐ์—๋Ÿฌ ์‹œ์ ๋ฉ”์‹œ์ง€friend ์šฐํšŒ๊ถŒ์žฅ
= deleteC++11+์ปดํŒŒ์ผ๋ช…ํ™•๋ถˆ๊ฐ€โ˜… ํ‘œ์ค€
private + no defC++98๋งํฌ๋ชจํ˜ธ๊ฐ€๋Šฅ๋ ˆ๊ฑฐ์‹œ๋งŒ
noncopyable ์ƒ์†์–‘์ชฝ์ปดํŒŒ์ผ/๋งํฌ๋ช…ํ™•๋ถˆ๊ฐ€๋ณด์ผ๋Ÿฌํ”Œ๋ ˆ์ดํŠธ ์ค„์ด๊ธฐ
move-onlyC++11+์ปดํŒŒ์ผ๋ช…ํ™•๋ถˆ๊ฐ€์ž์› ๊ด€๋ฆฌ
protected ์ƒ์„ฑ์ž์–‘์ชฝ์ปดํŒŒ์ผ๋ช…ํ™•๋ถˆ๊ฐ€(ํŒŒ์ƒ ์™ธ)์‹ฑ๊ธ€ํ„ด

์•”๋ฌต์  ์‚ญ์ œ โ€” ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์ž๋™์œผ๋กœ ๋ง‰๋Š” ๊ฒฝ์šฐ

์ž๊ธฐ๋Š” = delete๋ฅผ ์„ ์–ธํ•˜์ง€ ์•Š์•„๋„, ๋ฉค๋ฒ„ ์ค‘ ํ•˜๋‚˜๊ฐ€ ๋ณต์‚ฌ ๋ถˆ๊ฐ€๋Šฅํ•˜๋ฉด ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์ž๋™์œผ๋กœ ํด๋ž˜์Šค์˜ ๋ณต์‚ฌ๋ฅผ delete ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
class Container {
    std::unique_ptr<int> data;   // unique_ptr์ด ๋ณต์‚ฌ ๋ถˆ๊ฐ€
};

Container a;
Container b = a;   // โŒ ์ž๋™์œผ๋กœ deleted โ€” Container์˜ ๋ณต์‚ฌ ์ƒ์„ฑ์ž๊ฐ€ ์•”๋ฌต ์‚ญ์ œ๋จ
Container c = std::move(a);   // โœ… move๋Š” ์ž๋™ ์ƒ์„ฑ๋จ

์ฆ‰, ๋ฉค๋ฒ„์— unique_ptr์„ ๋‘๋Š” ๊ฒƒ๋งŒ์œผ๋กœ๋„ ํด๋ž˜์Šค๊ฐ€ ์ž๋™์œผ๋กœ move-only๊ฐ€ ๋ฉ๋‹ˆ๋‹ค. Rule of Zero์˜ ์ด์ƒ์  ํ™œ์šฉ.


4. Rule of Three / Five / Zero

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

์†Œ๋ฉธ์ž๊ฐ€ ์ž์›์„ ํ•ด์ œํ•œ๋‹ค๋ฉด, ๋ณต์‚ฌยท์ด๋™ ์˜๋ฏธ๋ก ๋„ ํ•จ๊ป˜ ์ •์˜ํ•ด์•ผ ์ผ๊ด€๋ฉ๋‹ˆ๋‹ค. ๊ฐ€์žฅ ์ข‹์€ ๊ฑด ์ •์˜๋ฅผ ์•ˆ ํ•˜๊ณ  RAII ํƒ€์ž…์— ์œ„์ž„ํ•˜๋Š” ๊ฒƒ(Rule of Zero)์ž…๋‹ˆ๋‹ค.

Rule of Three (C++98)

์†Œ๋ฉธ์ž, ๋ณต์‚ฌ ์ƒ์„ฑ์ž, ๋ณต์‚ฌ ๋Œ€์ž… ์—ฐ์‚ฐ์ž โ€” ํ•˜๋‚˜๋ผ๋„ ์ง์ ‘ ์ •์˜ํ•˜๋ฉด ์…‹ ๋‹ค ์ •์˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class BadString {
    char* data;
public:
    BadString(const char* s) {
        data = new char[strlen(s) + 1];
        strcpy(data, s);
    }
    ~BadString() { delete[] data; }   // โ† ์ง์ ‘ ์ •์˜
    // ๋ณต์‚ฌ ์ƒ์„ฑ์ž/๋Œ€์ž…์€ ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ๊ธฐ๋ณธ ์ƒ์„ฑ (์–•์€ ๋ณต์‚ฌ!)
};

BadString a("hello");
BadString b = a;   // ์–•์€ ๋ณต์‚ฌ โ€” a.data == b.data
// ์Šค์ฝ”ํ”„ ์ข…๋ฃŒ โ†’ ๋‘˜ ๋‹ค ๊ฐ™์€ data delete[] โ†’ ์ด์ค‘ ํ•ด์ œ UB!

ํ•ด๊ฒฐ โ€” Rule of Three ์ค€์ˆ˜:

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
class GoodString {
    char* data;
public:
    GoodString(const char* s) {
        data = new char[strlen(s) + 1];
        strcpy(data, s);
    }

    // 1) ์†Œ๋ฉธ์ž
    ~GoodString() { delete[] data; }

    // 2) ๋ณต์‚ฌ ์ƒ์„ฑ์ž (๊นŠ์€ ๋ณต์‚ฌ)
    GoodString(const GoodString& o) {
        data = new char[strlen(o.data) + 1];
        strcpy(data, o.data);
    }

    // 3) ๋ณต์‚ฌ ๋Œ€์ž… (์ž๊ธฐ ๋Œ€์ž… + ๊นŠ์€ ๋ณต์‚ฌ)
    GoodString& operator=(const GoodString& o) {
        if (this != &o) {
            delete[] data;
            data = new char[strlen(o.data) + 1];
            strcpy(data, o.data);
        }
        return *this;
    }
};

Rule of Five (C++11+)

C++11๋ถ€ํ„ฐ ์ด๋™ ์ƒ์„ฑ์ž์™€ ์ด๋™ ๋Œ€์ž… ์—ฐ์‚ฐ์ž๊ฐ€ ์ถ”๊ฐ€๋ฉ๋‹ˆ๋‹ค. ์†Œ๋ฉธ์ž/๋ณต์‚ฌ ์…‹ ์ค‘ ํ•˜๋‚˜๋ผ๋„ ์ง์ ‘ ์ •์˜ํ•˜๋ฉด 5์ข… ๋ชจ๋‘ ์ •์˜(๋˜๋Š” ๋ช…์‹œ์  ์‚ญ์ œ) ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

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
class GoodString {
    char* data;
public:
    GoodString(const char* s) { /* ... */ }

    // 1) ์†Œ๋ฉธ์ž
    ~GoodString() { delete[] data; }

    // 2) ๋ณต์‚ฌ ์ƒ์„ฑ์ž
    GoodString(const GoodString& o) { /* deep copy */ }

    // 3) ๋ณต์‚ฌ ๋Œ€์ž…
    GoodString& operator=(const GoodString& o) { /* ... */ }

    // 4) ์ด๋™ ์ƒ์„ฑ์ž (์†Œ์œ ๊ถŒ ์ด์ „)
    GoodString(GoodString&& o) noexcept : data(o.data) {
        o.data = nullptr;
    }

    // 5) ์ด๋™ ๋Œ€์ž…
    GoodString& operator=(GoodString&& o) noexcept {
        if (this != &o) {
            delete[] data;
            data = o.data;
            o.data = nullptr;
        }
        return *this;
    }
};

๋ณต์‚ฌ๋ฅผ ๋ง‰๊ณ  ์‹ถ๋‹ค๋ฉด 2ยท3์„ = delete๋กœ โ€” Rule of Five์˜ ํ•œ ํ˜•ํƒœ:

1
2
3
4
5
6
7
8
class FileHandle {
public:
    ~FileHandle();
    FileHandle(const FileHandle&) = delete;
    FileHandle& operator=(const FileHandle&) = delete;
    FileHandle(FileHandle&&) noexcept;
    FileHandle& operator=(FileHandle&&) noexcept;
};

Rule of Zero (๊ถŒ์žฅ)

์ž์› ๊ด€๋ฆฌ๋Š” RAII ํƒ€์ž…์— ์œ„์ž„ํ•˜๊ณ  ์‚ฌ์šฉ์ž๋Š” ํŠน๋ณ„ ๋ฉค๋ฒ„ ํ•จ์ˆ˜๋ฅผ ํ•˜๋‚˜๋„ ์ •์˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
8
9
10
class GoodString {
    std::string data;   // string์ด ์•Œ์•„์„œ ์ž์› ๊ด€๋ฆฌ
public:
    GoodString(const char* s) : data(s) {}
    // ์†Œ๋ฉธ์ž/๋ณต์‚ฌ/์ด๋™ ๋ชจ๋‘ ์ปดํŒŒ์ผ๋Ÿฌ ๊ธฐ๋ณธ ์ƒ์„ฑ์œผ๋กœ ์ถฉ๋ถ„
};

GoodString a("hello");
GoodString b = a;            // โœ… ๊นŠ์€ ๋ณต์‚ฌ (string์˜ ๋™์ž‘)
GoodString c = std::move(a); // โœ… ์ด๋™
1
2
3
4
5
6
7
8
9
10
class Player {
    std::unique_ptr<Inventory> inv;   // unique_ptr์ด ์•Œ์•„์„œ ๋‹จ๋… ์†Œ์œ 
    std::vector<Item> items;          // vector๊ฐ€ ์•Œ์•„์„œ ๊นŠ์€ ๋ณต์‚ฌ/์ด๋™
    std::string name;
public:
    // ์•„๋ฌด๊ฒƒ๋„ ์ •์˜ ์•ˆ ํ•จ โ†’ Player๋Š” ์ž๋™์œผ๋กœ:
    //   - ๋ณต์‚ฌ ๊ฐ€๋Šฅ (๋ชจ๋“  ๋ฉค๋ฒ„๊ฐ€ ๋ณต์‚ฌ ๊ฐ€๋Šฅํ•˜๋ฉด)
    //   - unique_ptr ๋•Œ๋ฌธ์— ์‚ฌ์‹ค์ƒ move-only๋กœ ์ž๋™ ๋ณ€ํ™˜
    //   - ์†Œ๋ฉธ์ž๋„ ์•Œ์•„์„œ ๋™์ž‘
};

๋น„๊ต ํ‘œ

๊ทœ์น™์‹œ๊ธฐ์ •์˜ํ•ด์•ผ ํ•  ๋ฉค๋ฒ„๊ถŒ์žฅ๋„
Rule of ThreeC++98์†Œ๋ฉธ์ž + ๋ณต์‚ฌ ์ƒ์„ฑ์ž + ๋ณต์‚ฌ ๋Œ€์ž…์ž์› ์ง์ ‘ ๊ด€๋ฆฌ ์‹œ
Rule of FiveC++11++ ์ด๋™ ์ƒ์„ฑ์ž + ์ด๋™ ๋Œ€์ž…์ž์› ์ง์ ‘ ๊ด€๋ฆฌ ์‹œ
Rule of ZeroC++11+์—†์Œ (RAII ํƒ€์ž… ์‚ฌ์šฉ)โ˜… ์ตœ์šฐ์„  ๊ถŒ์žฅ

5. move-only ํƒ€์ž… โ€” unique_ptr ํŒจํ„ด

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

๋ณต์‚ฌ๋Š” = delete, ์ด๋™์€ ํ—ˆ์šฉ โ€” ์ž์›์˜ ๋‹จ๋… ์†Œ์œ ๋ฅผ ํ‘œํ˜„ํ•˜๋ฉด์„œ๋„ ํ•จ์ˆ˜ ์ธ์ž/๋ฐ˜ํ™˜์„ ์ž์œ ๋กญ๊ฒŒ ํ•˜๋Š” ํŒจํ„ด์ž…๋‹ˆ๋‹ค. std::unique_ptr์ด ์ •ํ™•ํžˆ ์ด ํ˜•ํƒœ์ž…๋‹ˆ๋‹ค โ†’ 11๋ฒˆ [์Šค๋งˆํŠธ ํฌ์ธํ„ฐ] ์—ฐ๊ฒฐ.

unique_ptr์˜ ์‹ค์ œ ์ •์˜ (๊ฐ„๋žตํ™”)

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
template <typename T>
class unique_ptr {
    T* ptr;
public:
    explicit unique_ptr(T* p = nullptr) : ptr(p) {}
    ~unique_ptr() { delete ptr; }

    // ๋ณต์‚ฌ ๋ช…์‹œ์  ์‚ญ์ œ
    unique_ptr(const unique_ptr&) = delete;
    unique_ptr& operator=(const unique_ptr&) = delete;

    // ์ด๋™ ํ—ˆ์šฉ โ€” ์†Œ์œ ๊ถŒ ์ด์ „
    unique_ptr(unique_ptr&& o) noexcept : ptr(o.ptr) { o.ptr = nullptr; }
    unique_ptr& operator=(unique_ptr&& o) noexcept {
        if (this != &o) {
            delete ptr;
            ptr = o.ptr;
            o.ptr = nullptr;
        }
        return *this;
    }

    T* get() const { return ptr; }
    T& operator*() const { return *ptr; }
    T* operator->() const { return ptr; }
};

move-only๊ฐ€ ํ•จ์ˆ˜ ์ธ์ž/๋ฐ˜ํ™˜์—์„œ ์ž‘๋™ํ•˜๋Š” ๋ฐฉ์‹

1
2
3
4
5
6
7
8
9
10
11
12
std::unique_ptr<Widget> Make() {
    return std::make_unique<Widget>();   // ๋ฐ˜ํ™˜ ์‹œ move
}

void Take(std::unique_ptr<Widget> w) {   // ์†Œ์œ ๊ถŒ ์ด์ „ ๋ฐ›์Œ
    w->DoWork();
}   // w ์†Œ๋ฉธ โ†’ delete

auto p = Make();                  // โœ… ๋ฐ˜ํ™˜๊ฐ’ move
// Take(p);                       // โŒ ๋ณต์‚ฌ ๋ถˆ๊ฐ€
Take(std::move(p));               // โœ… ๋ช…์‹œ์  move โ€” ์†Œ์œ ๊ถŒ ์ด์ „
// ์ด ์‹œ์ ์— p == nullptr

๊ทธ๋Ÿผ ์™œ move๋Š” ์‚ด๋ฆฌ๋Š”๊ฐ€?

๋ณต์‚ฌ๋ฅผ ๋ง‰๋Š”๋‹ค๊ณ  ๊ฐ์ฒด๊ฐ€ ๋‹ค๋ฅธ ํ•จ์ˆ˜๋กœ ์ด๋™์กฐ์ฐจ ๋ชป ํ•˜๋ฉด ์‚ฌ์šฉ์„ฑ์ด ๋„ˆ๋ฌด ๋‚˜์ฉ๋‹ˆ๋‹ค. ์ด๋™์€ โ€œ์›๋ณธ์„ ๋น„์šฐ๊ณ  ์ƒˆ ๊ฐ์ฒด๋กœ ์ž์›์„ ์˜ฎ๊ธฐ๋Š”โ€ ์˜๋ฏธ ์ด๋ฏ€๋กœ ๋‹จ๋… ์†Œ์œ ๋ฅผ ๊นจ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

1
2
๋ณต์‚ฌ โ€” A์˜ ์ž์›์„ ๊ทธ๋Œ€๋กœ ๋‘๊ณ  B๊ฐ€ ๊ฐ™์€ ์ž์›์„ ๋˜ ๊ฐ€์ง (์ด์ค‘ ์†Œ์œ  โŒ)
์ด๋™ โ€” A์˜ ์ž์›์„ B๋กœ ์˜ฎ๊ธฐ๊ณ  A๋Š” ๋นˆ ์ƒํƒœ (๋‹จ๋… ์†Œ์œ  ์œ ์ง€ โœ…)

move-only๊ฐ€ ์ ํ•ฉํ•œ ์ž์›

  • ๋™์  ๋ฉ”๋ชจ๋ฆฌ (unique_ptr)
  • ์Šค๋ ˆ๋“œ ํ•ธ๋“ค (std::thread)
  • ์ž ๊ธˆ ๊ฐ์ฒด (std::lock_guard๋Š” move๋„ ๋ง‰์Œ, std::unique_lock์€ ํ—ˆ์šฉ)
  • ํŒŒ์ผ ์ŠคํŠธ๋ฆผ (std::ifstream โ€” C++11๋ถ€ํ„ฐ move-only)
  • ์†Œ์ผ“/๋ฎคํ…์Šค ๋ž˜ํผ

๊ฐ ์ž์›์˜ ๋ณต์‚ฌ/์ด๋™ ์ •์ฑ…์ด ์™œ ๊ทธ๋ ‡๊ฒŒ ๊ฒฐ์ •๋˜์—ˆ๋Š”์ง€๋Š” ๋‹ค์Œ 6์žฅ์—์„œ ์ž์„ธํžˆ ๋‹ค๋ฃน๋‹ˆ๋‹ค.


6. ๋‹จ๋… ์†Œ์œ  ์ž์› ์‹ฌํ™” โ€” ํŒŒ์ผ ํ•ธ๋“ค / ๋ฎคํ…์Šค / ์†Œ์ผ“

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

ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ๋ณต์‚ฌ๋ฅผ = deleteํ•˜๊ณ  move๋งŒ ์‚ด๋ฆฐ ์ด์œ ๋Š” ์ž์›์˜ ์˜๋ฏธ๋ก  ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. OS ํ•ธ๋“คยท์ž ๊ธˆยท์†Œ์ผ“์€ ๋ชจ๋‘ โ€œ๋™์‹œ์— ๋‘ ์ฑ…์ž„์ž๊ฐ€ ๋“ค ์ˆ˜ ์—†๋Š” ์ž์›โ€์ด๋ผ move-only๊ฐ€ ์ •๋‹ต์ž…๋‹ˆ๋‹ค.

6-1. ํŒŒ์ผ ํ•ธ๋“ค (File Handle)

OS๋Š” ์—ด๋ฆฐ ํŒŒ์ผ์„ ์ปค๋„์—์„œ ๊ด€๋ฆฌํ•˜๊ณ , ์‚ฌ์šฉ์ž ๊ณต๊ฐ„์—๋Š” ๊ทธ ์ž์›์„ ๊ฐ€๋ฆฌํ‚ค๋Š” ์‹๋ณ„์ž๋งŒ ๋…ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

ํ”Œ๋žซํผ์‹๋ณ„์ž ํƒ€์ž…๋‹ซ๊ธฐ ํ•จ์ˆ˜
C ํ‘œ์ค€FILE*fclose
POSIXint (file descriptor)close
WindowsHANDLE (void*)CloseHandle

๋ณต์‚ฌ ์‹œ ๋ฌด์—‡์ด ์œ„ํ—˜ํ•œ๊ฐ€?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// ์ง์ ‘ ๋งŒ๋“  ์•ˆ ์ข‹์€ ์˜ˆ
class MyFile {
    int fd = -1;
public:
    MyFile(const char* path) : fd(::open(path, O_RDONLY)) {}
    ~MyFile() { if (fd >= 0) ::close(fd); }
    // ์ปดํŒŒ์ผ๋Ÿฌ ๊ธฐ๋ณธ ๋ณต์‚ฌ = ์–•์€ ๋ณต์‚ฌ โ†’ fd ์ •์ˆ˜๋งŒ ๋ณต์‚ฌ๋จ
};

MyFile a("data.txt");  // fd = 5
MyFile b = a;          // a.fd == b.fd == 5
// ์Šค์ฝ”ํ”„ ์ข…๋ฃŒ:
//   b ์†Œ๋ฉธ โ†’ close(5)         OK
//   a ์†Œ๋ฉธ โ†’ close(5)         โŒ ์ด๋ฏธ ๋‹ซํžŒ fd ์žฌ close
//   ์‚ฌ์ด์— ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๊ฐ€ socket() ๋“ฑ์œผ๋กœ fd 5๋ฅผ ๋ฐ›์œผ๋ฉด
//   ์—‰๋šฑํ•œ ์ž์›์ด ๋‹ซํ˜€ fd ์žฌ์‚ฌ์šฉ ๊ณต๊ฒฉ(use-after-close) ๋ฐœ์ƒ

์ด ๋ฌธ์ œ ๋•Œ๋ฌธ์— POSIX๋Š” close ํ›„ ๊ฐ™์€ fd ๋ฒˆํ˜ธ๊ฐ€ ์ฆ‰์‹œ ์žฌ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์ด ๋ณด์•ˆ ์ด์Šˆ๋กœ ์ž์ฃผ ๊ฑฐ๋ก ๋ฉ๋‹ˆ๋‹ค.

ํ‘œ์ค€ ํ•ด๊ฒฐ โ€” std::fstream์€ C++11์—์„œ move-only๋กœ ์„ค๊ณ„

1
2
3
std::ifstream a("data.txt");
// std::ifstream b = a;          // โŒ deleted copy ctor
std::ifstream b = std::move(a);  // โœ… ํ•ธ๋“ค ์ด์ „. a๋Š” ๋‹ซํžŒ ์ƒํƒœ

std::ifstream ์ •์˜(๊ฐœ๋…์ ):

1
2
3
4
5
6
7
8
class basic_ifstream {
public:
    basic_ifstream(const basic_ifstream&) = delete;
    basic_ifstream& operator=(const basic_ifstream&) = delete;
    basic_ifstream(basic_ifstream&&);
    basic_ifstream& operator=(basic_ifstream&&);
    ~basic_ifstream();   // ๋‚ด๋ถ€ filebuf๊ฐ€ close
};

RAII๋กœ ์Šค์ฝ”ํ”„ ์ข…๋ฃŒ ์‹œ ์ž๋™ close โ†’ โ€œ๋‹ซ๋Š” ๊ฑธ ์žŠ์—ˆ๋‹คโ€ ๋ฒ„๊ทธ๊ฐ€ ์ปดํŒŒ์ผ๋Ÿฌ ์ฐจ์›์—์„œ ์‚ฌ๋ผ์ง.

6-2. ๋ฎคํ…์Šค (Mutex)

๋ฎคํ…์Šค๋Š” ์ž ๊ธˆ ์ƒํƒœ ์ž์ฒด๊ฐ€ ์ž์›์ด๋ผ ๋ณต์‚ฌ ์˜๋ฏธ๊ฐ€ ๋ณธ์งˆ์ ์œผ๋กœ ๋ชจํ˜ธํ•ฉ๋‹ˆ๋‹ค.

1
2
3
4
5
std::mutex m1;
// std::mutex m2 = m1;   // โŒ deleted โ€” ๊ทธ๋Ÿด๋“ฏํ•œ ๋‹ต์ด ์กด์žฌํ•˜์ง€ ์•Š์Œ
//   - ์ž ๊ธด ์ƒํƒœ๋กœ ๋ณต์‚ฌ? ๋‘ mutex๊ฐ€ ๊ฐ™์€ ์ž ๊ธˆ์„ ๊ณต์œ ?
//   - ํ’€๋ฆฐ ์ƒํƒœ๋กœ ๋ณต์‚ฌ? ๊ทธ๋Ÿฌ๋ฉด ์›๋ณธ ์ž ๊ธˆ์€ ์–ด๋–ป๊ฒŒ ๋จ?
//   - ์–ด๋А ๋‹ต์ด๋“  race condition์„ ๋งŒ๋“ ๋‹ค

ํ‘œ์ค€์€ ๋ณต์‚ฌยท์ด๋™ ๋ชจ๋‘ ์ฐจ๋‹จํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ์•ˆ์ „ํ•œ ๊ฒฐ๋ก ์ด๋ผ๊ณ  ํŒ๋‹จํ–ˆ์Šต๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
8
class mutex {
public:
    mutex() = default;
    ~mutex();
    mutex(const mutex&) = delete;
    mutex& operator=(const mutex&) = delete;
    // ์ด๋™๋„ ์ •์˜๋˜์ง€ ์•Š์Œ โ€” std::mutex๋Š” ๋น„-์ด๋™ ํƒ€์ž…
};

๊ทธ๋Ÿผ ์ž ๊ธˆ์„ ํ•จ์ˆ˜ ๊ฐ„์— ์–ด๋–ป๊ฒŒ ์˜ฎ๊ธฐ๋‚˜? โ€” RAII ๋ž˜ํผ 3์ข…์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๋ž˜ํผ๋ณต์‚ฌ์ด๋™์šฉ๋„
std::lock_guarddeletedelete๊ฐ€์žฅ ๊ฐ€๋ฒผ์šด ์Šค์ฝ”ํ”„ ์ž ๊ธˆ. ํ•จ์ˆ˜ ์•ˆ์—์„œ๋งŒ
std::unique_lockdeletedefault์ž ๊ธˆ ์†Œ์œ ๊ถŒ ์ด์ „ ๊ฐ€๋Šฅ. condition_variable๊ณผ ํ•จ๊ป˜ ํ•„์ˆ˜
std::scoped_lock (C++17)deletedelete๋ณต์ˆ˜ ๋ฎคํ…์Šค ๋ฐ๋“œ๋ฝ ๋ฐฉ์ง€(std::lock ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๋‚ด์žฅ)

unique_lock์ด move-only์ธ ์ด์œ :

1
2
3
4
5
6
7
8
9
10
11
std::unique_lock<std::mutex> AcquireLock(std::mutex& m) {
    std::unique_lock<std::mutex> lk(m);
    // ... ๊ฒ€์ฆ
    return lk;   // โœ… move๋กœ ํ˜ธ์ถœ์ž์—๊ฒŒ ์ž ๊ธˆ ์†Œ์œ ๊ถŒ ์ด์ „
}

void Worker(std::condition_variable& cv, std::mutex& m) {
    auto lk = AcquireLock(m);
    cv.wait(lk, [&]{ return ready; });   // โ† unique_lock ํ•„์ˆ˜
    // wait ๋‚ด๋ถ€๊ฐ€ lk.unlock()/lock()์„ ํ˜ธ์ถœ โ€” lock_guard๋กœ๋Š” ๋ถˆ๊ฐ€๋Šฅ
}

condition_variable::wait์€ ์ž ๊ธˆ์„ ์ผ์‹œ์ ์œผ๋กœ ํ’€์—ˆ๋‹ค๊ฐ€ ๋‹ค์‹œ ์žก์•„์•ผ ํ•˜๋ฏ€๋กœ ์ž ๊ธˆ ์†Œ์œ ๊ถŒ ์ด์ „์ด ๊ฐ€๋Šฅํ•œ unique_lock์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. lock_guard๋กœ๋Š” ๋™์ž‘ ์ž์ฒด๊ฐ€ ๋ถˆ๊ฐ€๋Šฅ.

6-3. ์†Œ์ผ“ (Socket)

์†Œ์ผ“ fd๋Š” ํŒŒ์ผ fd์™€ ๊ฐ™์€ ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด์ง€๋งŒ ์—ฐ๊ฒฐ ์ƒํƒœ์™€ ์†ก์ˆ˜์‹  ๋ฒ„ํผ๊ฐ€ ์ถ”๊ฐ€๋กœ ๋”ฐ๋ผ์˜ต๋‹ˆ๋‹ค.

1
2
3
4
5
// POSIX
int s = ::socket(AF_INET, SOCK_STREAM, 0);
// int s2 = s;   // ์ •์ˆ˜ ๋ณต์‚ฌ โ†’ ๊ฐ™์€ ์ปค๋„ ๊ฐ์ฒด ๋‘ ์ฑ…์ž„์ž
// close(s);    // ํ•œ์ชฝ์ด ๋‹ซ์œผ๋ฉด TCP ์—ฐ๊ฒฐ RST ์†ก์‹ 
// send(s2, ...) // ๋‹ค๋ฅธ ์ชฝ์€ ์ด๋ฏธ ๋Š๊ธด ์†Œ์ผ“์— ์†ก์‹  โ†’ EBADF or EPIPE

์—ฐ๊ฒฐ ์ƒํƒœ ๊ณต์œ  ๋ฌธ์ œ:

  • ํ•œ์ชฝ์ด send ๋„์ค‘ ๋‹ค๋ฅธ ์ชฝ์ด close โ†’ ๋ถ€๋ถ„ ์†ก์‹ , RST ํŒจํ‚ท ๋ฐœ์ƒ
  • ํ•œ์ชฝ์ด recv ๋Œ€๊ธฐ ์ค‘ ๋‹ค๋ฅธ ์ชฝ์ด close โ†’ ๋Œ€๊ธฐ ํ•จ์ˆ˜๊ฐ€ 0 ๋˜๋Š” ์—๋Ÿฌ๋กœ ๊นจ์ง
  • TCP ์ƒํƒœ ๋จธ์‹ (ESTABLISHED โ†’ FIN_WAIT โ†’ โ€ฆ)์ด ๋‘ ๊ฐ์ฒด ์‚ฌ์ด์—์„œ ์ผ๊ด€์„ฑ ์—†์ด ์ง„ํ–‰

Boost.Asio / ๋…๋ฆฝ Asio์˜ ์†Œ์ผ“ ์„ค๊ณ„:

1
2
3
4
5
6
7
8
9
namespace asio = boost::asio;

asio::io_context ctx;
asio::ip::tcp::socket sock(ctx);
sock.connect(endpoint);

// asio::ip::tcp::socket s2 = sock;            // โŒ deleted copy
asio::ip::tcp::socket s2 = std::move(sock);    // โœ… move โ€” ์†Œ์œ ๊ถŒ ์ด์ „
// ์ด ์‹œ์ ์— sock์€ ๋นˆ ์ƒํƒœ(์—ฐ๊ฒฐ ์—†์Œ)

Asio ์†Œ์ผ“ ํด๋ž˜์Šค ์ •์˜(๊ฐœ๋…์ ):

1
2
3
4
5
6
7
8
9
template <typename Protocol>
class basic_socket {
public:
    basic_socket(const basic_socket&) = delete;
    basic_socket& operator=(const basic_socket&) = delete;
    basic_socket(basic_socket&&) noexcept;
    basic_socket& operator=(basic_socket&&) noexcept;
    ~basic_socket();   // close() ํ˜ธ์ถœ
};

์™œ ๋น„๋™๊ธฐ ์ฝ”๋“œ์—์„œ move-only๊ฐ€ ํŠนํžˆ ์ค‘์š”ํ•œ๊ฐ€?

๋น„๋™๊ธฐ ํ•ธ๋“ค๋Ÿฌ๋Š” ์ฝœ๋ฐฑ ์ฒด์ธ ํ˜•ํƒœ๋กœ ์‹คํ–‰๋˜๋ฉฐ, ์†Œ์ผ“์˜ ์ˆ˜๋ช…์ด ์—ฌ๋Ÿฌ ์ฝœ๋ฐฑ์„ ๊ฑฐ์ณ ์ด์–ด์ง‘๋‹ˆ๋‹ค. ๋ณต์‚ฌ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋ฉด ํ•ธ๋“ค๋Ÿฌ๋งˆ๋‹ค ์†Œ์ผ“์„ ๋ณต์‚ฌํ•ด ๋“ค๊ณ  ๋‹ค๋‹ ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ด๋Š” ๊ณง ๊ฐ™์€ fd๊ฐ€ ์—ฌ๋Ÿฌ ํ•ธ๋“ค๋Ÿฌ์— ์‚ฐ์žฌํ•ด close ํƒ€์ด๋ฐ์ด ๋ฌด๋„ˆ์ง‘๋‹ˆ๋‹ค. move-only์ด๊ธฐ ๋•Œ๋ฌธ์— ์†Œ์ผ“ ์†Œ์œ ๊ถŒ์ด ํ•œ ์‹œ์ ์— ์ •ํ™•ํžˆ ํ•œ ํ•ธ๋“ค๋Ÿฌ์—๋งŒ ์žˆ๋‹ค๋Š” ๋ถˆ๋ณ€์„ฑ์ด ๊ฐ•์ œ๋ฉ๋‹ˆ๋‹ค.

1
2
3
4
5
6
asio::async_read(sock, buf, [s = std::move(sock)](auto ec, auto n) mutable {
    // ๋žŒ๋‹ค๊ฐ€ ์†Œ์ผ“ ์†Œ์œ  โ€” ๋‹ค์Œ ํ•ธ๋“ค๋Ÿฌ๋กœ ๋‹ค์‹œ std::move
    asio::async_write(s, buf, [s = std::move(s)](auto ec, auto n) {
        // ์ฝœ๋ฐฑ ์ฒด์ธ ๋๊นŒ์ง€ ๋‹จ๋… ์†Œ์œ  ๋ณด์žฅ
    });
});

์ž์›๋ณ„ ๋น„๊ต ์ข…ํ•ฉ

์ž์›ํ‘œ์ค€ ํƒ€์ž…๋ณต์‚ฌ์ด๋™์œ„ํ—˜ (๋ณต์‚ฌ ์‹œ)
ํŒŒ์ผstd::ifstream/ofstreamdeleteโœ…์ด์ค‘ close, fd ์žฌ์‚ฌ์šฉ ๊ณต๊ฒฉ
๋ฎคํ…์Šคstd::mutexdeletedelete์ž ๊ธˆ ์ƒํƒœ ์˜๋ฏธ ๋ชจํ˜ธ
์Šค์ฝ”ํ”„ ์ž ๊ธˆstd::lock_guarddeletedelete์ด์ค‘ unlock UB
์ž ๊ธˆ ์†Œ์œ ๊ถŒstd::unique_lockdeleteโœ…(์ด๋™ ๊ฐ€๋Šฅ โ€” cv.wait์šฉ)
๋ณต์ˆ˜ ์ž ๊ธˆstd::scoped_lockdeletedelete๋ฐ๋“œ๋ฝ ๋ฐฉ์ง€ ์•Œ๊ณ ๋ฆฌ์ฆ˜
์†Œ์ผ“ (Asio)asio::ip::tcp::socketdeleteโœ…์—ฐ๊ฒฐ ์ƒํƒœ ๊ณต์œ , RST, ๋ถ€๋ถ„ ์†ก์‹ 
๋™์  ๋ฉ”๋ชจ๋ฆฌstd::unique_ptrdeleteโœ…์ด์ค‘ delete, ํž™ ์†์ƒ

๊ณตํ†ต ํŒจํ„ด: ๋ชจ๋‘ ์ž์› ํ•ธ๋“ค + ์†Œ๋ฉธ์ž release + ๋ณต์‚ฌ delete + (ํ•„์š” ์‹œ) move ํ—ˆ์šฉ = RAII + move-only. ์‚ฌ์šฉ์ž ์ฝ”๋“œ๋Š” ์ด ํ‘œ์ค€ ํƒ€์ž…๋“ค์„ ๋ฉค๋ฒ„๋กœ ๋‘๊ธฐ๋งŒ ํ•˜๋ฉด ์•”๋ฌต์  ์‚ญ์ œ๋กœ ์ž๋™ move-only๊ฐ€ ๋ฉ๋‹ˆ๋‹ค โ†’ Rule of Zero.


7. ๊ฐ์ฒด ์Šฌ๋ผ์ด์‹ฑ ๋ฐฉ์ง€

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

๋‹คํ˜• ๊ฐ์ฒด๋ฅผ ๊ฐ’์œผ๋กœ ๋ณต์‚ฌํ•˜๋ฉด Derived ๋ถ€๋ถ„์ด ์ž˜๋ ค๋‚˜๊ฐ€ vptr๊นŒ์ง€ Base๋กœ ๊ณ ์ •๋ฉ๋‹ˆ๋‹ค. ๋‹คํ˜• ๊ธฐ๋ฐ˜ ํด๋ž˜์Šค๋Š” ๋ณดํ†ต noncopyable + virtual ์†Œ๋ฉธ์ž ์กฐํ•ฉ์œผ๋กœ ์„ค๊ณ„ํ•ฉ๋‹ˆ๋‹ค โ†’ 06_virtual_destructor.md ์—ฐ๊ฒฐ.

์Šฌ๋ผ์ด์‹ฑ ๋™์ž‘

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Animal {
public:
    virtual ~Animal() = default;
    virtual void Speak() const { std::cout << "..." << std::endl; }
};

class Dog : public Animal {
    std::string breed = "Shiba";
public:
    void Speak() const override { std::cout << "Woof! (" << breed << ")\n"; }
};

Dog d;
Animal a = d;   // ์Šฌ๋ผ์ด์‹ฑ! Dog::breed ์ž˜๋ ค๋‚˜๊ฐ, a์˜ vptr์€ Animal vtable ๊ฐ€๋ฆฌํ‚ด
a.Speak();      // "..." ์ถœ๋ ฅ (Dog::Speak ํ˜ธ์ถœ ์•ˆ ๋จ)

// ํ•จ์ˆ˜ ์ธ์ž์—์„œ๋„ ์ž์ฃผ ๋ฐœ์ƒ
void Process(Animal a) { a.Speak(); }   // โŒ ๊ฐ’์œผ๋กœ ๋ฐ›์Œ โ†’ ์Šฌ๋ผ์ด์‹ฑ
void Process(const Animal& a) { a.Speak(); }   // โœ… ์ฐธ์กฐ โ€” ๋‹คํ˜•์„ฑ ์œ ์ง€

ํ•ด๊ฒฐ 1 โ€” ๋‹คํ˜• ํด๋ž˜์Šค๋ฅผ noncopyable๋กœ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Animal {
public:
    Animal() = default;
    virtual ~Animal() = default;

    // ๋ณต์‚ฌ ๊ธˆ์ง€ โ€” ์Šฌ๋ผ์ด์‹ฑ ์›์ฒœ ์ฐจ๋‹จ
    Animal(const Animal&) = delete;
    Animal& operator=(const Animal&) = delete;

    virtual void Speak() const = 0;   // ์ถ”์ƒ ํด๋ž˜์Šค๋กœ๋„ ๋งŒ๋“ฆ
};

Animal a = d;     // โŒ ์ปดํŒŒ์ผ ์—๋Ÿฌ
Animal& ar = d;   // โœ… ์ฐธ์กฐ๋Š” OK

์ด ํŒจํ„ด์€ ๋‹คํ˜• ๊ฐ์ฒด๋Š” ํ•ญ์ƒ ํฌ์ธํ„ฐ/์ฐธ์กฐ๋กœ๋งŒ ๋‹ค๋ฃฌ๋‹ค๋Š” ๊ด€์šฉ๊ตฌ๋ฅผ ๊ฐ•์ œํ•ฉ๋‹ˆ๋‹ค.

ํ•ด๊ฒฐ 2 โ€” ์ถ”์ƒ ๊ธฐ๋ฐ˜ ํด๋ž˜์Šค(์ˆœ์ˆ˜ ๊ฐ€์ƒ ํ•จ์ˆ˜)

1
2
3
4
5
6
7
8
9
class Animal {
public:
    virtual ~Animal() = default;
    virtual void Speak() const = 0;   // ์ˆœ์ˆ˜ ๊ฐ€์ƒ โ†’ ์ถ”์ƒ ํด๋ž˜์Šค
};

Animal a;       // โŒ ์ถ”์ƒ ํด๋ž˜์Šค๋Š” ์ธ์Šคํ„ด์Šคํ™” ๋ถˆ๊ฐ€
Animal a2 = d;  // โŒ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋ถˆ๊ฐ€
Animal* p = new Dog();   // โœ… ํฌ์ธํ„ฐ๋กœ๋งŒ ๊ฐ€๋Šฅ

๋‹คํ˜• ๊ธฐ๋ฐ˜ ํด๋ž˜์Šค ๊ถŒ์žฅ ๊ตฌ์„ฑ

1
2
3
4
5
6
7
8
9
10
11
12
13
class Shape {
public:
    Shape() = default;
    virtual ~Shape() = default;                          // 1) virtual ์†Œ๋ฉธ์ž

    Shape(const Shape&) = delete;                        // 2) ๋ณต์‚ฌ ๊ธˆ์ง€
    Shape& operator=(const Shape&) = delete;

    Shape(Shape&&) = default;                            // 3) move๋„ ๋ณดํ†ต ์ฐจ๋‹จ
    Shape& operator=(Shape&&) = default;                 //    ๋˜๋Š” delete

    virtual double Area() const = 0;                     // 4) ์ถ”์ƒํ™”
};

์ด๊ฒŒ 6๋ฒˆ [virtual ์†Œ๋ฉธ์ž] + 12๋ฒˆ [๋ณต์‚ฌ ๊ธˆ์ง€] + 11๋ฒˆ [์Šค๋งˆํŠธ ํฌ์ธํ„ฐ๋กœ ๋‹ค๋ฃจ๊ธฐ] ์˜ ํ†ตํ•ฉ ํŒจํ„ด์ž…๋‹ˆ๋‹ค.

1
2
std::unique_ptr<Shape> s = std::make_unique<Circle>(5.0);
s->Area();   // ๋‹คํ˜•์„ฑ ์œ ์ง€, ์Šฌ๋ผ์ด์‹ฑ ์—†์Œ, virtual ์†Œ๋ฉธ์ž๋กœ ์•ˆ์ „ ํ•ด์ œ

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

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

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
"๊ฐ์ฒด ๋ณต์‚ฌ๋ฅผ ๋ง‰๋Š” ๋ฐฉ๋ฒ•, ์™œ ๋ง‰์•„์•ผ ํ•˜๋‚˜?"
         โ”‚
         โ”œโ”€ ์™œ ๋ง‰๋Š”๊ฐ€ (4๊ฐ€์ง€ ์ด์œ )
         โ”‚    โ””โ”€ "๋‹จ๋… ์†Œ์œ  ์ž์›์ด๋ž€ ๊ตฌ์ฒด์ ์œผ๋กœ?"
         โ”‚         โ””โ”€ "์ด์ค‘ ํ•ด์ œ๊ฐ€ ์™œ ์œ„ํ—˜ํ•œ๊ฐ€์š”?"
         โ”‚              โ””โ”€ "๊ทธ๋Ÿผ unique_ptr๋Š” ์–ด๋–ป๊ฒŒ ๋™์ž‘?" โ˜… 11๋ฒˆ ํšŒ๊ท€
         โ”‚
         โ”œโ”€ ์–ด๋–ป๊ฒŒ ๋ง‰๋Š”๊ฐ€
         โ”‚    โ”œโ”€ "= delete vs private ์ฐจ์ด?"
         โ”‚    โ”‚    โ””โ”€ "C++11 ์ด์ „์—” ์–ด๋–ป๊ฒŒ ํ–ˆ๋‚˜์š”?"
         โ”‚    โ””โ”€ "noncopyable ๋ฒ ์ด์Šค์˜ ์žฅ๋‹จ์ ?"
         โ”‚
         โ”œโ”€ Rule of N
         โ”‚    โ””โ”€ "Rule of Zero๊ฐ€ ๊ฐ€์žฅ ์ข‹์€ ์ด์œ ?"
         โ”‚         โ””โ”€ "์•”๋ฌต์  ์‚ญ์ œ๋Š” ์–ด๋–ป๊ฒŒ ๋™์ž‘?"
         โ”‚
         โ”œโ”€ move-only
         โ”‚    โ””โ”€ "์™œ ๋ณต์‚ฌ๋Š” ๋ง‰๊ณ  move๋Š” ์‚ด๋ฆฌ๋‚˜์š”?"
         โ”‚         โ””โ”€ "unique_ptr ๋‚ด๋ถ€ ๊ตฌ์กฐ๋Š”?" โ˜… 11๋ฒˆ ํšŒ๊ท€
         โ”‚
         โ””โ”€ ์Šฌ๋ผ์ด์‹ฑ
              โ””โ”€ "์Šฌ๋ผ์ด์‹ฑ์ด ์ •ํ™•ํžˆ ๋ฌด์—‡?"
                   โ””โ”€ "๋‹คํ˜• ํด๋ž˜์Šค๋Š” ์–ด๋–ป๊ฒŒ ์„ค๊ณ„?"
                        โ””โ”€ "virtual ์†Œ๋ฉธ์ž๋„ ๊ฐ™์ด ํ•„์š”ํ•œ๊ฐ€?" โ˜… 6๋ฒˆ ํšŒ๊ท€
                             โ””โ”€ "๊ทธ๋Ÿผ vtable์ด ์–ด๋–ค ์—ญํ• ?" โ˜… 5,8๋ฒˆ ํšŒ๊ท€

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

Q: ๋ณต์‚ฌ๋ฅผ ์™œ ๋ง‰์•„์•ผ ํ•˜๋‚˜์š”?

1
2
3
4
5
6
7
๋„ค ๊ฐ€์ง€ ์ด์œ :
1) ๋‹จ๋… ์†Œ์œ  ์ž์› โ€” ํŒŒ์ผ/๋ฎคํ…์Šค/์†Œ์ผ“/unique_ptr.
   ๋ณต์‚ฌํ•˜๋ฉด ๊ฐ™์€ ์ž์›์— ๋‘ ์ฑ…์ž„์ž๊ฐ€ ์ƒ๊ฒจ ์ด์ค‘ ํ•ด์ œยท์ž ๊ธˆ ์ถฉ๋Œ.
2) ๊ณ ๋น„์šฉ ๋ณต์‚ฌ โ€” ํฐ ์ปจํ…Œ์ด๋„ˆ ๊นŠ์€ ๋ณต์‚ฌ ๋น„์šฉ ์ฐจ๋‹จ.
3) ์‹ฑ๊ธ€ํ„ด/๋งค๋‹ˆ์ € โ€” ์ธ์Šคํ„ด์Šค๊ฐ€ 1๊ฐœ์—ฌ์•ผ ํ•˜๋Š” ๊ฐ์ฒด.
4) ์Šฌ๋ผ์ด์‹ฑ โ€” Base b = derived ์‹œ Derived ๋ถ€๋ถ„ ์†์‹ค.
์ฆ‰ "๋ณต์‚ฌ๊ฐ€ ์˜๋ฏธ์ƒ ๊นจ์ง€๋Š” ํƒ€์ž…"์€ ๋ง‰์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Q: = delete์™€ private ํŠธ๋ฆญ์˜ ์ฐจ์ด?

1
2
3
4
5
6
7
8
9
= delete (C++11):
  - ์ปดํŒŒ์ผ ํƒ€์ž„ ๋ช…ํ™•ํ•œ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€
  - friend ์•ˆ์—์„œ๋„ ํ˜ธ์ถœ ๋ถˆ๊ฐ€
  - public ์˜์—ญ์— ๋ช…์‹œ์ ์œผ๋กœ ์˜๋„ ํ‘œํ˜„

private + ์ •์˜ X (C++98):
  - ๋งํฌ ํƒ€์ž„ ์—๋Ÿฌ โ†’ ๋ฉ”์‹œ์ง€ ๋ชจํ˜ธ
  - friend ํ•จ์ˆ˜/๋ฉค๋ฒ„ ํ•จ์ˆ˜ ์•ˆ์—์„œ๋Š” ํ˜ธ์ถœ ๊ฐ€๋Šฅ (๊ตฌ๋ฉ)
  - C++11 ์ดํ›„๋กœ๋Š” ์‚ฌ์šฉ ์ด์œ  ์—†์Œ

Q: Rule of Three / Five / Zero๊ฐ€ ๋ญ”๊ฐ€์š”?

1
2
3
4
5
Rule of Three  โ€” ์†Œ๋ฉธ์ž/๋ณต์‚ฌ ์ƒ์„ฑ์ž/๋ณต์‚ฌ ๋Œ€์ž… ์ค‘ ํ•˜๋‚˜ ์ •์˜ โ†’ ์…‹ ๋‹ค ์ •์˜
                  ์ž์› ์ง์ ‘ ๊ด€๋ฆฌ(new/delete) ์‹œ ์ผ๊ด€์„ฑ ์œ ์ง€์šฉ
Rule of Five   โ€” + move ์ƒ์„ฑ์ž + move ๋Œ€์ž… (C++11)
Rule of Zero   โ€” RAII ํƒ€์ž…(string/vector/unique_ptr)์— ์œ„์ž„,
                  ํŠน๋ณ„ ๋ฉค๋ฒ„ ํ•จ์ˆ˜ ์ •์˜ ์•ˆ ํ•จ. ๊ฐ€์žฅ ๊ถŒ์žฅ.

Q: ์™œ ๋ณต์‚ฌ๋Š” ๋ง‰๊ณ  move๋Š” ์‚ด๋ฆฌ๋‚˜์š”?

1
2
3
4
5
6
๋ณต์‚ฌ: ์›๋ณธ ๊ทธ๋Œ€๋กœ ๋‘๊ณ  ์ƒˆ ๊ฐ์ฒด๊ฐ€ ๊ฐ™์€ ์ž์›์„ ๋˜ ๊ฐ€์ง โ†’ ๋‹จ๋… ์†Œ์œ  ๊นจ์ง
์ด๋™: ์›๋ณธ์„ ๋น„์šฐ๊ณ  ์ƒˆ ๊ฐ์ฒด๋กœ ์ž์›์„ ์˜ฎ๊น€ โ†’ ๋‹จ๋… ์†Œ์œ  ์œ ์ง€

unique_ptr์ด ์ด ํŒจํ„ด์˜ ์ •์„:
  ๋ณต์‚ฌ = delete, move ํ—ˆ์šฉ โ†’ ํ•จ์ˆ˜ ์ธ์ž/๋ฐ˜ํ™˜์€ std::move๋กœ ๊ฐ€๋Šฅ
  ๋‹จ๋… ์†Œ์œ ๋ผ๋Š” ์˜๋ฏธ๋ฅผ ๊นจ์ง€ ์•Š์œผ๋ฉด์„œ ์œ ์—ฐ์„ฑ ํ™•๋ณด

Q: ์Šฌ๋ผ์ด์‹ฑ์ด ๋ญ”๊ฐ€์š”?

1
2
3
4
5
6
7
class Base { virtual void f(); };
class Derived : public Base { int extra; };

Derived d;
Base b = d;   // ์Šฌ๋ผ์ด์‹ฑ! d.extra ์ž˜๋ ค๋‚˜๊ฐ, b.vptr์€ Base vtable
b.f();        // Base::f ํ˜ธ์ถœ (๋‹คํ˜•์„ฑ ๊นจ์ง)
// ๋‹คํ˜• ๊ธฐ๋ฐ˜ ํด๋ž˜์Šค๋Š” ๋ณดํ†ต ๋ณต์‚ฌ๋ฅผ ๋ง‰๊ณ  ํฌ์ธํ„ฐ/์ฐธ์กฐ๋กœ๋งŒ ๋‹ค๋ฃจ๋„๋ก ์„ค๊ณ„

Q: ๋ฉค๋ฒ„์— unique_ptr์ด ์žˆ์œผ๋ฉด ์ž๋™์œผ๋กœ ์–ด๋–ป๊ฒŒ ๋˜๋‚˜์š”?

1
2
3
4
์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ํด๋ž˜์Šค์˜ ๋ณต์‚ฌ ์ƒ์„ฑ์ž/๋Œ€์ž…์„ ์•”๋ฌต์ ์œผ๋กœ = delete ์ฒ˜๋ฆฌ.
์ด์œ : unique_ptr์ด ๋ณต์‚ฌ ๋ถˆ๊ฐ€ โ†’ ๋ฉค๋ฒ„ ๋ณต์‚ฌ๊ฐ€ ๋ถˆ๊ฐ€๋Šฅ
๊ฒฐ๊ณผ: ์‚ฌ์šฉ์ž๊ฐ€ ์•„๋ฌด๊ฒƒ๋„ ์•ˆ ์จ๋„ ํด๋ž˜์Šค๊ฐ€ ์ž๋™์œผ๋กœ move-only.
์ด๊ฒƒ์ด Rule of Zero์˜ ์ด์ƒ์  ํ™œ์šฉ โ€” ์ž์› ๊ด€๋ฆฌ ์œ„์ž„์˜ ํšจ๊ณผ.

Q: ๋‹คํ˜• ๊ธฐ๋ฐ˜ ํด๋ž˜์Šค๋Š” ์–ด๋–ป๊ฒŒ ์„ค๊ณ„ํ•ด์•ผ ํ•˜๋‚˜์š”?

1
2
3
4
5
6
7
ํ‘œ์ค€ ํŒจํ„ด 4์ข…:
1) virtual ~Base() โ€” ๊ธฐ๋ฐ˜ ํฌ์ธํ„ฐ delete ์‹œ ํŒŒ์ƒ ์†Œ๋ฉธ์ž ์ฒด์ธ ํ˜ธ์ถœ ๋ณด์žฅ
2) ๋ณต์‚ฌ = delete  โ€” ์Šฌ๋ผ์ด์‹ฑ ์ฐจ๋‹จ, ํ•ญ์ƒ ํฌ์ธํ„ฐ/์ฐธ์กฐ๋กœ๋งŒ ๋‹ค๋ฃจ๊ธฐ
3) move๋„ ๋ณดํ†ต = delete โ€” ์•ˆ์ „ํ•œ ๊ธฐ๋ณธ๊ฐ’
4) ์ˆœ์ˆ˜ ๊ฐ€์ƒ ํ•จ์ˆ˜ โ€” ์ถ”์ƒ ํด๋ž˜์Šค๋กœ ๋งŒ๋“ค๋ฉด ์ธ์Šคํ„ด์Šคํ™” ์ž์ฒด ๋ถˆ๊ฐ€

์‚ฌ์šฉ ์‹œ: std::unique_ptr<Base>๋กœ ๋‹คํ˜• ๊ฐ์ฒด๋ฅผ ๋‹ค๋ฃธ โ†’ 11๋ฒˆ ์Šค๋งˆํŠธ ํฌ์ธํ„ฐ ์—ฐ๊ฒฐ

Q: std::fstream์ด ๋ณต์‚ฌ ๋ถˆ๊ฐ€์ธ ์ด์œ ๋Š”?

1
2
3
4
5
6
ํŒŒ์ผ ํ•ธ๋“ค(FILE*/fd)์€ OS๊ฐ€ ๊ด€๋ฆฌํ•˜๋Š” ๋‹จ๋… ์ž์›.
๋ณต์‚ฌํ•˜๋ฉด ๊ฐ™์€ fd๋ฅผ ๋‘ ๊ฐ์ฒด๊ฐ€ ๋“ค์–ด ์ด์ค‘ close ๋ฐœ์ƒ.
์ด์ค‘ close๋Š” ๋‹จ์ˆœ ์—๋Ÿฌ๊ฐ€ ์•„๋‹ˆ๋ผ fd ์žฌ์‚ฌ์šฉ ๊ณต๊ฒฉ์œผ๋กœ ์ด์–ด์งˆ ์ˆ˜ ์žˆ์Œ โ€”
๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๊ฐ€ ๊ฐ™์€ fd ๋ฒˆํ˜ธ๋กœ ์ƒˆ ์ž์›์„ ๋ฐ›์€ ์‹œ์ ์— ๋‘ ๋ฒˆ์งธ close๊ฐ€
์ผ์–ด๋‚˜๋ฉด ์—‰๋šฑํ•œ ์ž์›์ด ๋‹ซํ˜€ ์ •๋ณด ๋ˆ„์ถœ/์†์ƒ ๊ฐ€๋Šฅ.
C++11์—์„œ ifstream/ofstream/fstream์„ move-only๋กœ ์„ค๊ณ„ํ•ด RAII ๋‹ซ๊ธฐ ๋ณด์žฅ.

Q: std::mutex๋Š” ์™œ ์ด๋™์กฐ์ฐจ ์•ˆ ๋˜๋‚˜์š”?

1
2
3
4
5
6
7
8
๋ฎคํ…์Šค๋Š” ์ž ๊ธˆ ์ƒํƒœ ์ž์ฒด๊ฐ€ ์ž์›์ด๋ผ ๋ณต์‚ฌยท์ด๋™ ์˜๋ฏธ๊ฐ€ ๋ณธ์งˆ์ ์œผ๋กœ ๋ชจํ˜ธ:
  - ์ž ๊ธด ์ฑ„๋กœ ์˜ฎ๊ธฐ๋ฉด? ์˜ฎ๊ธด ํ›„ unlock ์ฑ…์ž„์€ ๋ˆ„๊ตฌ?
  - ํ’€์–ด์„œ ์˜ฎ๊ธฐ๋ฉด? ์ž„๊ณ„ ์˜์—ญ ๋ณดํ˜ธ๊ฐ€ ๊นจ์ง
์–ด๋–ค ๋‹ต์„ ๊ณจ๋ผ๋„ race condition์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด ํ‘œ์ค€์€ ๋‘˜ ๋‹ค = delete.
๋Œ€์‹  RAII ๋ž˜ํผ๋กœ ์ž ๊ธˆ์„ ๋‹ค๋ฃธ:
  lock_guard  โ€” ๊ฐ€์žฅ ๊ฐ€๋ฒผ์›€. ๋ณต์‚ฌยท์ด๋™ ๋ชจ๋‘ delete
  unique_lock โ€” ์ด๋™ ํ—ˆ์šฉ. condition_variable.wait()์ด ์š”๊ตฌ
  scoped_lock โ€” ๋ณต์ˆ˜ ๋ฎคํ…์Šค ๋ฐ๋“œ๋ฝ ๋ฐฉ์ง€(C++17)

Q: unique_lock๊ณผ lock_guard์˜ ์ฐจ์ด๋Š”?

1
2
3
4
5
6
7
8
9
10
lock_guard:
  - ๋ณต์‚ฌยท์ด๋™ ๋ชจ๋‘ = delete
  - ๊ฐ€์žฅ ๊ฐ€๋ฒผ์›€ (fast path ์ž ๊ธˆ)
  - ํ•จ์ˆ˜ ์•ˆ ์Šค์ฝ”ํ”„ ์ž ๊ธˆ ์ „์šฉ
unique_lock:
  - ๋ณต์‚ฌ = delete, move ํ—ˆ์šฉ
  - ์ž ๊ธˆ์„ ํ•จ์ˆ˜ ๊ฐ„ ์ด์ „ ๊ฐ€๋Šฅ (๋ฐ˜ํ™˜ยท์ธ์ž ํŒจ์Šค)
  - cv.wait()์ฒ˜๋Ÿผ ์ผ์‹œ์ ์œผ๋กœ unlock/lock ํ•ด์•ผ ํ•˜๋Š” API์— ํ•„์ˆ˜
  - ์•ฝ๊ฐ„ ๋” ๋ฌด๊ฑฐ์›€ (์†Œ์œ  ์—ฌ๋ถ€ ํ”Œ๋ž˜๊ทธ ๋ณด์œ )
์„ ํƒ ๊ธฐ์ค€: cv.wait ๋˜๋Š” ์ž ๊ธˆ ์ด์ „ ํ•„์š” โ†’ unique_lock, ๊ทธ ์™ธ โ†’ lock_guard

Q: ์†Œ์ผ“์„ ๋ณต์‚ฌํ•˜๋ฉด ์™œ ์œ„ํ—˜ํ•œ๊ฐ€์š”?

1
2
3
4
5
6
7
8
์†Œ์ผ“์€ fd + ์—ฐ๊ฒฐ ์ƒํƒœ(TCP state) + ์†ก์ˆ˜์‹  ๋ฒ„ํผ๊ฐ€ ๋ฌถ์ธ ์ž์›.
๋ณต์‚ฌ ์‹œ ๊ฐ™์€ fd๋ฅผ ๋‘ ๊ฐ์ฒด๊ฐ€ ๋“ค๋ฉด:
  1) ํ•œ์ชฝ send ์ค‘ ๋‹ค๋ฅธ ์ชฝ close โ†’ ๋ถ€๋ถ„ ์†ก์‹ /RST ํŒจํ‚ท, TCP ์ƒํƒœ ์˜ค์—ผ
  2) ํ•œ์ชฝ recv ๋Œ€๊ธฐ ์ค‘ close โ†’ ๋Œ€๊ธฐ ํ•จ์ˆ˜๊ฐ€ 0/์—๋Ÿฌ๋กœ ๊นจ์ง
  3) ์ด์ค‘ close๋กœ fd ์žฌ์‚ฌ์šฉ ๊ณต๊ฒฉ
Boost.Asio/asio๋Š” socket์„ move-only๋กœ ์„ค๊ณ„ โ€” ๋น„๋™๊ธฐ ํ•ธ๋“ค๋Ÿฌ ์ฒด์ธ์—์„œ
์†Œ์ผ“ ์†Œ์œ ๊ถŒ์ด ํ•œ ์‹œ์ ์— ์ •ํ™•ํžˆ ํ•œ ํ•ธ๋“ค๋Ÿฌ์—๋งŒ ์žˆ๋„๋ก ๊ฐ•์ œ.
๋žŒ๋‹ค ์บก์ฒ˜์—์„œ std::move(sock)์œผ๋กœ ์ด์ „ํ•˜๋ฉฐ ์ฝœ๋ฐฑ ์ฒด์ธ ์ง„ํ–‰.

Q: shared_ptr์€ ์™œ ๋ณต์‚ฌ๊ฐ€ ๊ฐ€๋Šฅํ•œ๊ฐ€์š”?

1
2
3
4
5
6
shared_ptr์˜ ์˜๋ฏธ๋Š” "๊ณต์œ  ์†Œ์œ " โ€” ์—ฌ๋Ÿฌ ๊ฐ์ฒด๊ฐ€ ํ•จ๊ป˜ ์ž์›์„ ์ฑ…์ž„์ง.
๋ณต์‚ฌ ์‹œ ์ฐธ์กฐ ์นด์šดํŠธ๋งŒ ์ฆ๊ฐ€์‹œํ‚ค๋ฏ€๋กœ ์ž์› ์ž์ฒด๋Š” ์—ฌ์ „ํžˆ 1๊ฐœ.
strong_count == 0์ด ๋˜์–ด์•ผ delete ๋จ โ†’ ์ด์ค‘ ํ•ด์ œ ์•ˆ ์ผ์–ด๋‚จ.
์ฆ‰ ๋ณต์‚ฌ๊ฐ€ ์•ˆ์ „ํ•œ ์ด์œ ๋Š” shared_ptr์ด "๋‹จ๋… ์†Œ์œ "๊ฐ€ ์•„๋‹Œ "๊ณต์œ  ์†Œ์œ "
์˜๋ฏธ๋ก ์„ ๊ฐ–๊ธฐ ๋•Œ๋ฌธ. ๋ณต์‚ฌ ๊ฐ€๋Šฅ/๋ถˆ๊ฐ€๋Šฅ์€ ํƒ€์ž…์˜ ์˜๋ฏธ๊ฐ€ ๊ฒฐ์ •ํ•จ.
(11๋ฒˆ ์Šค๋งˆํŠธ ํฌ์ธํ„ฐ ํšŒ๊ณ  1ยท4๋ฒˆ๊ณผ ๋™์ผ ํ๋ฆ„)

9. ์–ธ๋ฆฌ์–ผ์—์„œ์˜ ๋ณต์‚ฌ ๊ธˆ์ง€

๋‘ ๊ฐ€์ง€ ๋ณต์‚ฌ ์ •์ฑ… โ€” UObject vs ์ผ๋ฐ˜ C++ ๊ฐ์ฒด

1
2
3
4
5
6
7
8
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  UObject ๊ณ„์—ด              โ”‚  ์ผ๋ฐ˜ C++ ๊ฐ์ฒด               โ”‚
โ”‚  (AActor, UComponent ๋“ฑ)   โ”‚  (FVector, ์ปค์Šคํ…€ struct)    โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  ๋ณธ์งˆ์ ์œผ๋กœ ๋ณต์‚ฌ ๋ถˆ๊ฐ€      โ”‚  USTRUCT / ์ผ๋ฐ˜ C++ ๊ทœ์น™     โ”‚
โ”‚  NewObject<T>๋กœ๋งŒ ์ƒ์„ฑ     โ”‚  ๋ณต์‚ฌ ํ—ˆ์šฉ ๋˜๋Š”              โ”‚
โ”‚  GC๊ฐ€ ๋‹จ๋… ์ฑ…์ž„            โ”‚  UE_NONCOPYABLE / FNoncopyableโ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

UE_NONCOPYABLE ๋งคํฌ๋กœ

์–ธ๋ฆฌ์–ผ์ด ์ œ๊ณตํ•˜๋Š” ํ•œ ์ค„ noncopyable ์„ ์–ธ์ž…๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
8
class FMyResource
{
public:
    FMyResource();
    ~FMyResource();

    UE_NONCOPYABLE(FMyResource)   // โ† ํ•œ ์ค„๋กœ ๋ณต์‚ฌยท์ด๋™ ๋ชจ๋‘ = delete
};

UE_NONCOPYABLE์€ ๋งคํฌ๋กœ๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ™•์žฅ๋ฉ๋‹ˆ๋‹ค(๊ฐœ๋…์ ):

1
2
3
#define UE_NONCOPYABLE(TypeName) \
    TypeName(const TypeName&) = delete; \
    TypeName& operator=(const TypeName&) = delete;

์–ธ๋ฆฌ์–ผ ๊ณต์‹ ๊ฐ€์ด๋“œ๋ผ์ธ์€ ์ž์› ๊ด€๋ฆฌ ํด๋ž˜์Šค์— ์ด ๋งคํฌ๋กœ๋ฅผ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

FNoncopyable ๋ฒ ์ด์Šค ํด๋ž˜์Šค

1
2
3
4
class FMyManager : private FNoncopyable
{
    // ์ž๋™์œผ๋กœ ๋ณต์‚ฌ ๋ถˆ๊ฐ€
};

๋‚ด๋ถ€์ ์œผ๋กœ ์œ„ ํŒจํ„ด(noncopyable ๋ฒ ์ด์Šค ์ƒ์†)์„ ๊ทธ๋Œ€๋กœ ์ ์šฉํ•œ ํ˜•ํƒœ์ž…๋‹ˆ๋‹ค.

UObject๋Š” ์™œ ๋ณธ์งˆ์ ์œผ๋กœ ๋ณต์‚ฌ ๋ถˆ๊ฐ€์ธ๊ฐ€?

1
2
3
4
5
6
7
8
9
10
11
UCLASS()
class AMyActor : public AActor
{
    GENERATED_BODY()
};

AMyActor a;                  // โŒ ์ปดํŒŒ์ผ ์—๋Ÿฌ โ€” UObject๋Š” ์Šคํƒ์— ๋ชป ๋งŒ๋“ฆ
AMyActor* p = new AMyActor();// โŒ ์ž˜๋ชป๋œ ์‚ฌ์šฉ โ€” operator new๊ฐ€ GC ํ’€๋กœ ๋ผ์šฐํŒ… ๋จ

// โœ… ์˜ฌ๋ฐ”๋ฅธ ์ƒ์„ฑ
AMyActor* Actor = NewObject<AMyActor>(this);

์ด์œ :

  • UObject๋Š” GC๊ฐ€ ๋‹จ๋… ๊ด€๋ฆฌ โ€” ๋‘ ์ธ์Šคํ„ด์Šค๊ฐ€ ๊ฐ™์€ ์ž์›์„ ๋“ค๋ฉด GC ์ถ”์  ๊นจ์ง
  • ์ƒ์„ฑ์ž๊ฐ€ protected / GENERATED_BODY()๊ฐ€ ์ž๋™ ์ƒ์„ฑํ•˜๋Š” ๊ธฐ๋ฐ˜ ๊ตฌ์กฐ๊ฐ€ ๋ณต์‚ฌ ์ฐจ๋‹จ
  • AActor๋Š” World ๋ ˆ๋ฒจ์— ๋“ฑ๋ก๋œ ๋‹จ๋… ๊ฐ์ฒด โ€” ์˜๋ฏธ์ƒ ๋ณต์‚ฌ ๋ถˆ๊ฐ€

TUniquePtr / TSharedPtr ์˜ ๋ณต์‚ฌ ์ •์ฑ…

11๋ฒˆ์—์„œ ๋ณธ ๊ฒƒ๊ณผ ๋™์ผํ•˜๊ฒŒ:

ํƒ€์ž…๋ณต์‚ฌ์ด๋™๋น„๊ณ 
TUniquePtr<T>โŒ deleteโœ…move-only โ€” unique_ptr ๋Œ€์‘
TSharedPtr<T>โœ… (์นด์šดํŠธ++)โœ…๊ณต์œ  ์†Œ์œ  โ€” shared_ptr ๋Œ€์‘
TSharedRef<T>โœ… (null ๋ถˆ๊ฐ€)โœ…ํ•ญ์ƒ ์œ ํšจํ•œ ๊ณต์œ  ์†Œ์œ 
TWeakPtr<T>โœ… (๊ด€์ฐฐ๋งŒ)โœ…์•ฝํ•œ ์ฐธ์กฐ
TWeakObjectPtr<T>โœ… (UObject ์•ฝํ•œ ์ฐธ์กฐ)โœ…GC ํ™˜๊ฒฝ ์•ฝํ•œ ์ฐธ์กฐ
1
2
3
TUniquePtr<FMyData> a = MakeUnique<FMyData>();
// TUniquePtr<FMyData> b = a;        // โŒ ๋ณต์‚ฌ ๋ถˆ๊ฐ€
TUniquePtr<FMyData> b = MoveTemp(a); // โœ… move (std::move ๋Œ€์‘)

USTRUCT(BlueprintType) ์˜ ๋ณต์‚ฌ ์˜๋ฏธ

USTRUCT๋Š” ๋ณดํ†ต ๊ฐ’ ํƒ€์ž… โ€” ๋ณต์‚ฌ ๊ฐ€๋Šฅ์„ ๊ธฐ๋ณธ์œผ๋กœ ํ•ฉ๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
USTRUCT(BlueprintType)
struct FInventoryItem
{
    GENERATED_BODY()

    UPROPERTY() FName Name;
    UPROPERTY() int32 Count = 0;
};

FInventoryItem a;
FInventoryItem b = a;   // โœ… ๋ณต์‚ฌ โ€” UStruct ์˜๋„๋œ ๋™์ž‘

๋ณต์‚ฌ๋ฅผ ๋ง‰์œผ๋ ค๋ฉด ์ผ๋ฐ˜ C++ ๊ทœ์น™๋Œ€๋กœ = delete:

1
2
3
4
5
6
7
8
USTRUCT()
struct FBigData
{
    GENERATED_BODY()
    FBigData() = default;
    FBigData(const FBigData&) = delete;
    FBigData& operator=(const FBigData&) = delete;
};

๋น„๊ต ํ‘œ

ย std์–ธ๋ฆฌ์–ผ
๋ณต์‚ฌ ์ฐจ๋‹จ ๋งคํฌ๋กœ์ง์ ‘ = deleteUE_NONCOPYABLE(T)
noncopyable ๋ฒ ์ด์Šคboost::noncopyableFNoncopyable
move-only ์Šค๋งˆํŠธ ํฌ์ธํ„ฐunique_ptrTUniquePtr (MoveTemp)
๊ณต์œ  ์†Œ์œ shared_ptrTSharedPtr / TSharedRef
๋ณต์‚ฌ ๋ถˆ๊ฐ€ ๊ฐ์ฒด์ง์ ‘ noncopyable ์ž‘์„ฑUObject (์ž๋™)
์Šฌ๋ผ์ด์‹ฑ ์ฐจ๋‹จvirtual ์†Œ๋ฉธ์ž + deleteUObject ๋ณธ์งˆ + virtual

์ฐธ๊ณ 

  • 11_smart_pointer.md โ€” unique_ptr(move-only)ยทshared_ptr(๋ณต์‚ฌ ๊ฐ€๋Šฅ) ์†Œ์œ ๊ถŒ ๋ชจ๋ธ, ์˜ค๋Š˜ ํšŒ๊ณ  1ยท4๋ฒˆ ์—ฐ๊ฒฐ
  • 09_rtti_raii.md โ€” RAII ์ž์› ๊ด€๋ฆฌ, Rule of Zero์˜ ์ด์ƒ์  ํ™œ์šฉ
  • 06_virtual_destructor.md โ€” ๋‹คํ˜• ๊ธฐ๋ฐ˜ ํด๋ž˜์Šค + ์Šฌ๋ผ์ด์‹ฑ ์ฐจ๋‹จ + virtual ์†Œ๋ฉธ์ž ํ†ตํ•ฉ ํŒจํ„ด
  • 08_vtable_deepdive.md โ€” ์Šฌ๋ผ์ด์‹ฑ ์‹œ vptr์ด Base๋กœ ๊ณ ์ •๋˜๋Š” ์ด์œ 
์ด ๊ธฐ์‚ฌ๋Š” ์ €์ž‘๊ถŒ์ž์˜ CC BY 4.0 ๋ผ์ด์„ผ์Šค๋ฅผ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค.

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

Powered by Jekyll with Chirpy theme

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