Move 문법

(λ³€μˆ˜μ˜) 할당은 _μ†Œμœ κΆŒ_을 λ³€μˆ˜ 간에 μ΄λ™μ‹œν‚΅λ‹ˆλ‹€:

fn main() {
    let s1: String = String::from("Hello!");
    let s2: String = s1;
    println!("s2: {s2}");
    // println!("s1: {s1}");
}
  • s1을 s2에 ν• λ‹Ήν•˜μ—¬ μ†Œμœ κΆŒμ„ μ΄μ „μ‹œν‚΅λ‹ˆλ‹€.
  • s1의 μŠ€μ½”ν”„κ°€ μ’…λ£Œλ˜λ©΄ 아무 일도 μ—†μŠ΅λ‹ˆλ‹€: μ™œλƒν•˜λ©΄ s1은 μ•„λ¬΄λŸ° μ†Œμœ κΆŒμ΄ μ—†κΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€.
  • s2의 μŠ€μ½”ν”„κ°€ μ’…λ£Œλ˜λ©΄ λ¬Έμžμ—΄ λ°μ΄ν„°λŠ” ν•΄μ œλ©λ‹ˆλ‹€.

s2둜 이동 μ „ λ©”λͺ¨λ¦¬:

StackHeaps1ptrHello!len4capacity4

s2둜 이동 ν›„ λ©”λͺ¨λ¦¬:

StackHeaps1ptrHello!len4capacity4s2ptrlen4capacity4(inaccessible)

값을 ν•¨μˆ˜μ— μ „λ‹¬ν• λ•Œ, κ·Έ 값은 λ§€κ°œλ³€μˆ˜μ— ν• λ‹Ήλ©λ‹ˆλ‹€. μ΄λ•Œ μ†Œμœ κΆŒμ˜ 이동이 μΌμ–΄λ‚©λ‹ˆλ‹€:

fn say_hello(name: String) {
    println!("μ•ˆλ…•ν•˜μ„Έμš” {name}")
}

fn main() {
    let name = String::from("Alice");
    say_hello(name);
    // say_hello(name);
}
This slide should take about 5 minutes.
  • μ΄λŠ” C++κ³Ό μ •λ°˜λŒ€ μž„μ„ μ„€λͺ…ν•˜μ„Έμš”. C++μ—μ„œλŠ” 볡사가 기본이고, std::move λ₯Ό μ΄μš©ν•΄μ•Όλ§Œ (그리고 이동 μƒμ„±μžκ°€ μ •μ˜λ˜μ–΄ μžˆμ–΄μ•Όλ§Œ!) μ†Œμœ κΆŒ 이전이 λ©λ‹ˆλ‹€.

  • μ‹€μ œλ‘œ μ΄λ™λ˜λŠ” 것은 μ†Œμœ κΆŒμΌ λΏμž…λ‹ˆλ‹€. λ¨Έμ‹  μ½”λ“œ λ ˆλ²¨μ—μ„œ 데이터 볡사가 일어날 μ§€ 말 지에 λŒ€ν•œ 것은 컴파일러 λ‚΄λΆ€μ—μ„œ μΌμ–΄λ‚˜λŠ” μ΅œμ ν™” λ¬Έμ œμž…λ‹ˆλ‹€. 이런 λ³΅μ‚¬λŠ” μ΅œμ ν™” κ³Όμ •μ—μ„œ μ œκ±°κ°€ λ©λ‹ˆλ‹€.

  • μ •μˆ˜μ™€ 같은 κ°„λ‹¨ν•œ 값듀은 Copy (뒀에 μ„€λͺ…ν•©λ‹ˆλ‹€)둜 λ§ˆν‚Ήλ  수 μžˆμŠ΅λ‹ˆλ‹€.

  • λŸ¬μŠ€νŠΈμ—μ„œλŠ” λ³΅μ‚¬ν• λ•Œμ—λŠ” λͺ…μ‹œμ μœΌλ‘œ clone을 μ‚¬μš©ν•©λ‹ˆλ‹€.

say_hello 예:

  • say_helloν•¨μˆ˜μ˜ 첫번째 ν˜ΈμΆœμ‹œ mainν•¨μˆ˜λŠ” μžμ‹ μ΄ κ°€μ§„ name에 λŒ€ν•œ μ†Œμœ κΆŒμ„ ν¬κΈ°ν•˜λ―€λ‘œ, 이후 mainν•¨μˆ˜μ—μ„œλŠ” name을 μ‚¬μš©ν•  수 μ—†μŠ΅λ‹ˆλ‹€.
  • name에 ν• λ‹Ήλ˜μžˆλŠ” νž™ λ©”λͺ¨λ¦¬λŠ” say_helloν•¨μˆ˜μ˜ λμ—μ„œ ν•΄μ œλ©λ‹ˆλ‹€.
  • mainν•¨μˆ˜μ—μ„œ name을 참쑰둜 전달(빌림)ν•˜κ³ (&name), say_helloμ—μ„œ λ§€κ°œλ³€μˆ˜λ₯Ό μ°Έμ‘°ν˜•μœΌλ‘œ μˆ˜μ •ν•œλ‹€λ©΄ mainν•¨μˆ˜λŠ” name의 μ†Œμœ κΆŒμ„ μœ μ§€ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • λ˜λŠ” 첫번째 호좜 μ‹œ mainν•¨μˆ˜μ—μ„œ name을 λ³΅μ œν•˜μ—¬ 전달할 μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€.(name.clone())
  • λŸ¬μŠ€νŠΈλŠ” 이동을 기본으둜 ν•˜κ³  볡제λ₯Ό λͺ…μ‹œμ μœΌλ‘œ μ„ μ–Έν•˜λ„λ‘ λ§Œλ“¬μœΌλ‘œ, μ˜λ„μΉ˜ μ•Šκ²Œ 볡사본을 λ§Œλ“œλŠ” 것이 C++μ—μ„œλ³΄λ‹€ μ–΄λ ΅μŠ΅λ‹ˆλ‹€.

더 μ‚΄νŽ΄λ³΄κΈ°

Defensive Copies in Modern C++

Modern C++은 이 문제λ₯Ό λ‹€λ₯΄κ²Œ ν•΄κ²°ν•©λ‹ˆλ‹€:

std::string s1 = "Cpp";
std::string s2 = s1;  // s1의 데이터λ₯Ό λ³΅μ œν•©λ‹ˆλ‹€.
  • s1의 νž™ λ°μ΄ν„°λŠ” 볡제되고, s2λŠ” 독립적인 볡사본을 μ–»μŠ΅λ‹ˆλ‹€.
  • s1 와 s2의 μŠ€μ½”ν”„κ°€ μ’…λ£Œλ˜λ©΄ 각각의 λ©”λͺ¨λ¦¬κ°€ ν•΄μ œλ©λ‹ˆλ‹€.

볡사 μ „:

StackHeaps1ptrCpplen3capacity3

볡사 ν›„:

StackHeaps1ptrCpplen3capacity3s2ptrCpplen3capacity3

ν‚€ 포인트:

  • C++λŠ” Rust와 μ•½κ°„ λ‹€λ₯Έ 선택을 ν–ˆμŠ΅λ‹ˆλ‹€. =λŠ” 데이터λ₯Ό λ³΅μ‚¬ν•˜λ―€λ‘œ λ¬Έμžμ—΄ 데이터가 ν΄λ‘ λ˜μ–΄μ•Ό ν•©λ‹ˆλ‹€. κ·Έλ ‡μ§€ μ•ŠμœΌλ©΄ λ¬Έμžμ—΄ 쀑 ν•˜λ‚˜κ°€ λ²”μœ„λ₯Ό λ²—μ–΄λ‚  λ•Œ double-freeκ°€ λ°œμƒν•©λ‹ˆλ‹€.

  • C++μ—λŠ” 값을 이동할 수 μžˆλŠ” μ‹œμ μ„ λ‚˜νƒ€λ‚΄λŠ” 데 μ‚¬μš©λ˜λŠ” std::move도 μžˆμŠ΅λ‹ˆλ‹€. μ˜ˆκ°€ s2 = std::move(s1)μ΄μ—ˆλ‹€λ©΄ νž™ 할당이 λ°œμƒν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. 이동 ν›„μ—λŠ” s1이 μœ νš¨ν•˜μ§€λ§Œ μ§€μ •λ˜μ§€ μ•Šμ€ μƒνƒœκ°€ λ©λ‹ˆλ‹€. Rust와 달리 ν”„λ‘œκ·Έλž˜λ¨ΈλŠ” s1을 계속 μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

  • Rust와 달리, C++의 =λŠ” λ³΅μ‚¬λ˜κ±°λ‚˜ μ΄λ™λ˜λŠ” νƒ€μž…μ— 따라 κ²°μ •λœ μž„μ˜μ˜ μ½”λ“œλ₯Ό μ‹€ν–‰ν•  수 μžˆμŠ΅λ‹ˆλ‹€.