๊ธ€์“ด์ด ๋ณด๊ด€๋ฌผ: ์†Œ์žฅ ๋งˆ

std :: move ()๋Š” ๋ฌด์—‡์ด๋ฉฐ ์–ธ์ œ ์‚ฌ์šฉํ•ด์•ผํ•ฉ๋‹ˆ๊นŒ? ์‚ฌ์šฉํ•ด์•ผํ•ฉ๋‹ˆ๊นŒ? ์ข‹์€ ๋งํฌ๋ฅผ ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

  1. ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?
  2. ๋ฌด์—‡์„ํ•ฉ๋‹ˆ๊นŒ?
  3. ์–ธ์ œ ์‚ฌ์šฉํ•ด์•ผํ•ฉ๋‹ˆ๊นŒ?

์ข‹์€ ๋งํฌ๋ฅผ ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค.



๋‹ต๋ณ€

C ++ 11 R- ๊ฐ’ ์ฐธ์กฐ ๋ฐ ์ด๋™ ์ƒ์„ฑ์ž์— ๋Œ€ํ•œ Wikipedia ํŽ˜์ด์ง€

  1. C ++ 11์—์„œ๋Š” ๋ณต์‚ฌ ์ƒ์„ฑ์ž ์™ธ์—๋„ ๊ฐ์ฒด์— ์ด๋™ ์ƒ์„ฑ์ž๊ฐ€์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    ๋˜ํ•œ ๋ณต์‚ฌ ํ• ๋‹น ์—ฐ์‚ฐ์ž ์™ธ์—๋„ ์ด๋™ ํ• ๋‹น ์—ฐ์‚ฐ์ž๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
  2. ๊ฐ์ฒด์˜ ์œ ํ˜•์ด โ€œrvalue-referenceโ€( Type &&) ์ธ ๊ฒฝ์šฐ ์ด๋™ ์ƒ์„ฑ์ž ๋Œ€์‹  ์ด๋™ ์ƒ์„ฑ์ž๊ฐ€ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค .
  3. std::move() ๊ฐ์ฒด์— ๋Œ€ํ•œ rvalue-reference๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ๊ฐ์ฒด์—์„œ ์ด๋™ํ•  ์ˆ˜ ์žˆ๋„๋กํ•˜๋Š” ์บ์ŠคํŠธ์ž…๋‹ˆ๋‹ค.

๋ณต์‚ฌ๋ณธ์„ ํ”ผํ•˜๋Š” ์ƒˆ๋กœ์šด C ++ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์ด๋™ ์ƒ์„ฑ์ž๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด a std::vector๋Š” ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ๋‚ด๋ถ€ ํฌ์ธํ„ฐ๋ฅผ ์ƒˆ ๊ฐ์ฒด์— ๋ณต์‚ฌํ•˜์—ฌ ์ด๋™ ๋œ ๊ฐ์ฒด๋ฅผ ์ด๋™ ๋œ ์ƒํƒœ๋กœ ์œ ์ง€ํ•˜๋ฏ€๋กœ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ๋ณต์‚ฌํ•˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ C ++-์œ ํšจํ•ฉ๋‹ˆ๋‹ค.

์ด๋™ ์˜๋ฏธ, rvalue, ์™„๋ฒฝํ•œ ์ „๋‹ฌ์„ ์œ„ํ•ด ์ธํ„ฐ๋„ท ๊ฒ€์ƒ‰์„ ์‹œ๋„ํ•˜์‹ญ์‹œ์˜ค.


๋‹ต๋ณ€

1. โ€œ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?โ€

std::move() ๊ธฐ์ˆ ์ ์œผ๋กœ๋Š” ํ•จ์ˆ˜ ์ด์ง€๋งŒ ์‹ค์ œ๋กœ ๋Š” ํ•จ์ˆ˜ ๊ฐ€ ์•„๋‹ˆ๋ผ๊ณ  ๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค . ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ํ‘œํ˜„์‹์˜ ๊ฐ’์„ ๊ณ ๋ คํ•˜๋Š” ๋ฐฉ์‹ ์‚ฌ์ด ์˜ ๋ณ€ํ™˜๊ธฐ ์ž…๋‹ˆ๋‹ค.

2. โ€œ๋ฌด์—‡์„ํ•ฉ๋‹ˆ๊นŒ?โ€

๊ฐ€์žฅ ๋จผ์ € ์ฃผ๋ชฉํ•  ๊ฒƒ์€ std::move() ์‹ค์ œ๋กœ ์•„๋ฌด๊ฒƒ๋„ ์›€์ง์ด์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ ์ž…๋‹ˆ๋‹ค. ํ‘œํ˜„์‹์„ ์ด๋ฆ„์ด ์ง€์ •๋œ ๋ณ€์ˆ˜์™€ ๊ฐ™์€ lvalue ์—์„œ xvalue๋กœ ๋ณ€ํ™˜ ํ•ฉ๋‹ˆ๋‹ค. xvalue๋Š” ์ปดํŒŒ์ผ๋Ÿฌ์—๊ฒŒ ๋‹ค์Œ์„ ์•Œ๋ ค์ค๋‹ˆ๋‹ค.

๋‹น์‹ ์€ ์ €๋ฅผ ์•ฝํƒˆํ•˜๊ณ , ๋‚ด๊ฐ€ ๊ฐ€์ง€๊ณ ์žˆ๋Š” ๊ฒƒ์„ ์˜ฎ๊ธฐ๊ณ  ๋‹ค๋ฅธ ๊ณณ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค (์–ด์จŒ๋“  ๊ณง ํŒŒ๊ดด ๋  ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์—) โ€œ.

์ฆ‰,๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ std::move(x)์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์‹์ธ์ข…์„ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค x. ๋”ฐ๋ผ์„œ x๋ฉ”๋ชจ๋ฆฌ์— ์ž์ฒด ๋ฒ„ํผ๊ฐ€ ์žˆ๋‹ค๋ฉด std::move()์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ๋‹ค๋ฅธ ๊ฐ์ฒด๋ฅผ ์†Œ์œ  ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

prvalue (์˜ˆ : ์ž„์‹œ๋กœ ์ „๋‹ฌ๋˜๋Š”) ์—์„œ ์ด๋™ํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ ๊ฑฐ์˜ ์œ ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

3. โ€œ์–ธ์ œ ์‚ฌ์šฉํ•ด์•ผํ•ฉ๋‹ˆ๊นŒ?โ€

์ด ์งˆ๋ฌธ์„ํ•˜๋Š” ๋˜ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์€ โ€œ๊ธฐ์กด ๊ฐ์ฒด์˜ ์ž์›์„ ์–ด๋–ป๊ฒŒ ์ž ์‹ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?โ€์ž…๋‹ˆ๋‹ค. ๊ธ€์Ž„, ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•œ๋‹ค๋ฉด ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ๋งŒ๋“  ์ž„์‹œ ๊ฐ์ฒด๋ฅผ ๋งŽ์ด ์‚ฌ์šฉํ•˜์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ฃผ๋กœ ์ƒ์„ฑ์ž, ์—ฐ์‚ฐ์ž ๋ฉ”์„œ๋“œ, ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜๊ณผ ๊ฐ™์€ ํ•จ์ˆ˜ ๋“ฑ์—์„œ ๊ฐ์ฒด๋ฅผ ์ž๋™์œผ๋กœ ๋งŽ์ด ์ƒ์„ฑํ•˜๊ณ  ํŒŒ๊ดดํ•˜๋Š” ์žฅ์†Œ ์—์„œ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ๋ฌผ๋ก , ๊ทธ๊ฒƒ์€ ๋‹จ์ง€ ๊ฒฝํ—˜์˜ ๋ฒ•์น™์ž…๋‹ˆ๋‹ค.

์ผ๋ฐ˜์ ์œผ๋กœ ๋ณต์‚ฌ ๋Œ€์‹  ํ•œ ๊ฐœ์ฒด์—์„œ ๋‹ค๋ฅธ ๊ฐœ์ฒด๋กœ ๋ฆฌ์†Œ์Šค๋ฅผ โ€˜์ด๋™โ€™ํ•ฉ๋‹ˆ๋‹ค. @Guillaume ์€์ด ํŽ˜์ด์ง€์— ๋งํฌ๋˜์–ด ์žˆ์œผ๋ฉฐ ๊ฐ„๋‹จํ•œ ์˜ˆ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‘ ๊ฐœ์˜ ๊ฐ์ฒด๋ฅผ ์ ์€ ๋ณต์‚ฌ๋กœ ๋ฐ”๊พธ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

template <class T>
swap(T& a, T& b) {
    T tmp(a);   // we now have two copies of a
    a = b;      // we now have two copies of b (+ discarded a copy of a)
    b = tmp;    // we now have two copies of tmp (+ discarded a copy of b)
}

์ด๋™์„ ์‚ฌ์šฉํ•˜๋ฉด ์ž์›์„ ๋ณต์‚ฌํ•˜์ง€ ์•Š๊ณ  ๊ตํ™˜ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

template <class T>
swap(T& a, T& b) {
    T tmp(std::move(a));
    a = std::move(b);
    b = std::move(tmp);
}

T์˜ˆ vector<int>๋ฅผ ๋“ค์–ด ํฌ๊ธฐ๊ฐ€ n ์ผ ๋•Œ ์–ด๋–ค ์ผ์ด ๋ฐœ์ƒํ•˜๋Š”์ง€ ์ƒ๊ฐํ•ด๋ณด์‹ญ์‹œ์˜ค . ์ฒซ ๋ฒˆ์งธ ๋ฒ„์ „์—์„œ๋Š” 3 * n ์š”์†Œ๋ฅผ ์ฝ๊ณ  ์”๋‹ˆ๋‹ค. ๋‘ ๋ฒˆ์งธ ๋ฒ„์ „์—์„œ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ฒกํ„ฐ ๋ฒ„ํผ์— ๋Œ€ํ•œ 3 ๊ฐœ์˜ ํฌ์ธํ„ฐ์™€ 3 ๊ฐœ์˜ ๋ฒ„ํผ ํฌ๊ธฐ ๋งŒ ์ฝ๊ณ  ์”๋‹ˆ๋‹ค. ๋ฌผ๋ก , ์ˆ˜์—… T์€ ์–ด๋–ป๊ฒŒ ์›€์ง์ด๋Š”์ง€๋ฅผ ์•Œ์•„์•ผํ•ฉ๋‹ˆ๋‹ค. ์ด ํด๋ž˜์Šค๊ฐ€ T์ž‘๋™ํ•˜๋ ค๋ฉด ํด๋ž˜์Šค ์— ์ด๋™ ํ• ๋‹น ์—ฐ์‚ฐ์ž์™€ ํด๋ž˜์Šค ๋ฅผ ์œ„ํ•œ ์ด๋™ ์ƒ์„ฑ์ž๊ฐ€ ์žˆ์–ด์•ผํ•ฉ๋‹ˆ๋‹ค.


๋‹ต๋ณ€

๋ณต์‚ฌํ•˜์ง€ ์•Š๊ณ  ๊ฐ์ฒด์˜ ๋‚ด์šฉ์„ ๋‹ค๋ฅธ ๊ณณ์œผ๋กœ โ€œ์ „์†กโ€ํ•ด์•ผ ํ•  ๋•Œ ์ด๋™์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค (์ฆ‰, ๋‚ด์šฉ์ด ๋ณต์ œ๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— unique_ptr๊ณผ ๊ฐ™์ด ๋ณต์‚ฌ ํ•  ์ˆ˜์—†๋Š” ์ผ๋ถ€ ๊ฐ์ฒด์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค). std :: move๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ์ฒด๊ฐ€ ๋ณต์‚ฌํ•˜์ง€ ์•Š๊ณ  ์ž„์‹œ ๊ฐ์ฒด์˜ ๋‚ด์šฉ์„ ๊ฐ€์ ธ์™€ ๋งŽ์€ ์‹œ๊ฐ„์„ ์ ˆ์•ฝ ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ๋งํฌ๋Š” ์ •๋ง ๋„์›€์ด๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

http://thbecker.net/articles/rvalue_references/section_01.html

๋‹ต๋ณ€์ด ๋„ˆ๋ฌด ๋Šฆ์–ด์ง€๋ฉด ์ฃ„์†กํ•˜์ง€๋งŒ std :: move์— ๋Œ€ํ•œ ์ข‹์€ ๋งํฌ๋ฅผ ์ฐพ๊ณ  ์žˆ์—ˆ์œผ๋ฉฐ ์œ„์˜ ๋งํฌ๊ฐ€ โ€œaustereโ€๋ณด๋‹ค ์•ฝ๊ฐ„ ์ปธ์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ r- ๊ฐ’ ์ฐธ์กฐ์— ์ค‘์ ์„๋‘๊ณ  ์žˆ์œผ๋ฉฐ, ์—ฌ๊ธฐ์„œ๋Š” ์ปจํ…์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•ด์•ผํ•˜๋ฉฐ ๋” ์ž์„ธํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.์ด ๋งํฌ๋ฅผ ์—ฌ๊ธฐ์— ๊ณต์œ ํ•˜๊ณ  ์‹ถ์—ˆ์Šต๋‹ˆ๋‹ค.


๋‹ต๋ณ€

Q : ๋ฌด์—‡์ž…๋‹ˆ๊นŒ std::move?

A : std::move()rvalue ์ฐธ์กฐ๋กœ ์บ์ŠคํŠธํ•˜๊ธฐ์œ„ํ•œ C ++ ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.

๊ฐ„๋‹จ std::move(t)ํ•˜๊ฒŒ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

static_cast<T&&>(t);

rvalue๋Š” ๋ณ€์ˆ˜์— ์ €์žฅ๋˜์ง€ ์•Š๋Š” ์ค‘๊ฐ„ ํ•จ์ˆ˜ ๊ฒฐ๊ณผ์™€ ๊ฐ™์ด์ด๋ฅผ ์ •์˜ํ•˜๋Š” ํ‘œํ˜„์‹์„ ๋„˜์–ด ์ง€์†๋˜์ง€ ์•Š๋Š” ์ž„์‹œ ๊ฐ’์ž…๋‹ˆ๋‹ค.

int a = 3; // 3 is a rvalue, does not exist after expression is evaluated
int b = a; // a is a lvalue, keeps existing after expression is evaluated

std :: move ()์˜ ๊ตฌํ˜„์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด N2027 : โ€œRvalue ์ฐธ์กฐ์— ๋Œ€ํ•œ ๊ฐ„๋žตํ•œ ์†Œ๊ฐœโ€ ์— ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค.

template <class T>
typename remove_reference<T>::type&&
std::move(T&& a)
{
    return a;
}

๋ณด์‹œ๋‹ค์‹œํ”ผ , ๊ฐ’ ( ), ์ฐธ์กฐ ์œ ํ˜• ( ) ๋˜๋Š” rvalue ์ฐธ์กฐ ( )๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ˜ธ์ถœํ•˜๋”๋ผ๋„ ์ƒ๊ด€์—†์ด std::move๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค .T&&TT&T&&

Q : ๋ฌด์—‡์„ํ•ฉ๋‹ˆ๊นŒ?

A : ์บ์ŠคํŠธ๋กœ์„œ ๋Ÿฐํƒ€์ž„ ์ค‘์— ์•„๋ฌด๊ฒƒ๋„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ปดํŒŒ์ผ๋Ÿฌ์—๊ฒŒ ์ฐธ์กฐ๋ฅผ rvalue๋กœ ๊ณ„์† ๊ณ ๋ คํ•˜๊ณ  ์žˆ๋‹ค๊ณ  ์•Œ๋ฆฌ๋Š” ๊ฒƒ์€ ์ปดํŒŒ์ผ ํƒ€์ž„์—๋งŒ ๊ด€๋ จ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

foo(3 * 5); // obviously, you are calling foo with a temporary (rvalue)

int a = 3 * 5;
foo(a);     // how to tell the compiler to treat `a` as an rvalue?
foo(std::move(a)); // will call `foo(int&& a)` rather than `foo(int a)` or `foo(int& a)`

ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ :

  • ๋…ผ์Ÿ์˜ ์‚ฌ๋ณธ์„ ๋งŒ๋“œ์‹ญ์‹œ์˜ค
  • ๋ณต์‚ฌ ์ƒ์„ฑ์ž ํ˜ธ์ถœ
  • ์ธ์ˆ˜ ๊ฐ์ฒด ๋ณ€๊ฒฝ

Q : ์–ธ์ œ ์‚ฌ์šฉํ•ด์•ผํ•ฉ๋‹ˆ๊นŒ?

A : std::movervalue (์ž„์‹œ ํ‘œํ˜„์‹)๊ฐ€ ์•„๋‹Œ ์ธ์ˆ˜๋กœ ์ด๋™ ์˜๋ฏธ๋ฅผ ์ง€์›ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋ ค๋Š” ๊ฒฝ์šฐ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํ›„์† ์งˆ๋ฌธ์„ ์ œ๊ธฐํ•ฉ๋‹ˆ๋‹ค.

  • ์ด๋™ ์˜๋ฏธ ๋ž€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ๋ณต์‚ฌ ์‹œ๋งจํ‹ฑ๊ณผ ๋Œ€์กฐ์ ์œผ๋กœ ์‹œ๋งจํ‹ฑ ์ด๋™์€ ์˜ค๋ธŒ์ ํŠธ์˜ ๋ฉค๋ฒ„๊ฐ€ ๋‹ค๋ฅธ ์˜ค๋ธŒ์ ํŠธ์˜ ๋ฉค๋ฒ„๋ฅผ ๋ณต์‚ฌํ•˜๋Š” ๋Œ€์‹  โ€˜์ทจ๋“โ€™ํ•˜์—ฌ ์ดˆ๊ธฐํ™”๋˜๋Š” ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๊ธฐ์ˆ ์ž…๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ โ€˜์ธ๊ณ„โ€™๋Š” ํฌ์ธํ„ฐ ๋ฐ ๋ฆฌ์†Œ์Šค ํ•ธ๋“ค์—์„œ๋งŒ ์˜๋ฏธ๊ฐ€ ์žˆ์œผ๋ฉฐ, ๊ธฐ๋ณธ ๋ฐ์ดํ„ฐ๊ฐ€ ์•„๋‹Œ ํฌ์ธํ„ฐ ๋˜๋Š” ์ •์ˆ˜ ํ•ธ๋“ค์„ ๋ณต์‚ฌํ•˜์—ฌ ์ €๋ ดํ•˜๊ฒŒ ์ „์†กํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์ด๋™ ์‹œ๋งจํ‹ฑ์„ ์ง€์›ํ•˜๋Š” ํด๋ž˜์Šค์™€ ๊ฐ์ฒด๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ๋ฉค๋ฒ„๋ฅผ ๋ณต์‚ฌํ•˜๋Š” ๋Œ€์‹  ๋ฉค๋ฒ„๋ฅผ ์ „์†กํ•˜๋Š” ๊ฒƒ์ด ๋„์›€์ด๋˜๋Š” ๊ฒฝ์šฐ ์ž์‹ ์˜ ํด๋ž˜์Šค์—์„œ ์ด๋™ ์˜๋ฏธ๋ก ์„ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์€ ๊ฐœ๋ฐœ์ž์˜ ์ฑ…์ž„์ž…๋‹ˆ๋‹ค. ์ด๋™ ์˜๋ฏธ๋ก ์„ ๊ตฌํ˜„ํ•˜๋ฉด ์ด๋™ ์˜๋ฏธ๋ก ์„ ์‚ฌ์šฉํ•˜์—ฌ ํด๋ž˜์Šค๋ฅผ ํšจ์œจ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐ ๋Œ€ํ•œ ์ง€์›์„ ์ถ”๊ฐ€ ํ•œ ๋งŽ์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํ”„๋กœ๊ทธ๋ž˜๋จธ์˜ ์ž‘์—…์œผ๋กœ๋ถ€ํ„ฐ ์ง์ ‘ ํ˜œํƒ์„ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์™œ ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์Šค์Šค๋กœ ์•Œ์•„๋‚ผ ์ˆ˜ ์—†์Šต๋‹ˆ๊นŒ? ๋‹ฌ๋ฆฌ ๋งํ•˜์ง€ ์•Š๋Š” ํ•œ ์ปดํŒŒ์ผ๋Ÿฌ๋Š” ํ•จ์ˆ˜์˜ ๋‹ค๋ฅธ ์˜ค๋ฒ„๋กœ๋“œ๋ฅผ ํ˜ธ์ถœ ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์ •๊ทœ ๋˜๋Š” ์ด๋™ ๋ฒ„์ „์˜ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ด์•ผํ•˜๋Š”์ง€ ์„ ํƒํ•˜๋„๋ก ๋„์™€์•ผํ•ฉ๋‹ˆ๋‹ค.

  • ์–ด๋–ค ์ƒํ™ฉ์—์„œ ์ปดํŒŒ์ผ๋Ÿฌ์—๊ฒŒ ๋ณ€์ˆ˜๋ฅผ rvalue๋กœ ์ทจ๊ธ‰ํ•ด์•ผํ•œ๋‹ค๊ณ  ๋งํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๊นŒ? ์ด๋Š” ์ค‘๊ฐ„ ๊ฒฐ๊ณผ๊ฐ€ ๋ณต๊ตฌ ๋  ์ˆ˜ ์žˆ์Œ์„ ์•Œ๊ณ ์žˆ๋Š” ํ…œํ”Œ๋ฆฌํŠธ ๋˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํ•จ์ˆ˜์—์„œ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.


๋‹ต๋ณ€

std :: move ์ž์ฒด๋Š” ์‹ค์ œ๋กœ ๋งŽ์€ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ฐ์ฒด์˜ ์ด๋™ ์ƒ์„ฑ์ž๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ์ง€๋งŒ ์‹ค์ œ๋กœ ์œ ํ˜• ๋ณ€ํ™˜์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค (lvalue ๋ณ€์ˆ˜๋ฅผ rvalue๋กœ ์บ์ŠคํŒ…ํ•˜์—ฌ ํ•ด๋‹น ๋ณ€์ˆ˜๋ฅผ ์ด๋™ ์ƒ์„ฑ์ž ๋˜๋Š” ํ• ๋‹น ์—ฐ์‚ฐ์ž์— ์ธ์ˆ˜๋กœ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Œ).

๋”ฐ๋ผ์„œ std :: move๋Š” ์ด๋™ ์˜๋ฏธ๋ก ์„ ์‚ฌ์šฉํ•˜๋Š” ์„ ๊ตฌ์ž๋กœ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ์ด๋™ ์˜๋ฏธ๋ก ์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ž„์‹œ ๊ฐ์ฒด๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ํšจ์œจ์ ์ธ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

๊ฐ์ฒด ๊ณ ๋ ค A = B + C + D + E + F;

์ด๊ฒƒ์€ ๋ฉ‹์ง„ ์ฝ”๋“œ์ด์ง€๋งŒ E + F๋Š” ์ž„์‹œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ D + temp๋Š” ๋‹ค๋ฅธ ์ž„์‹œ ๊ฐ์ฒด ๋“ฑ์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ํด๋ž˜์Šค์˜ ๊ฐ ์ผ๋ฐ˜ โ€œ+โ€์—ฐ์‚ฐ์ž์—์„œ ๋”ฅ ์นดํ”ผ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด

Object Object::operator+ (const Object& rhs) {
    Object temp (*this);
    // logic for adding
    return temp;
}

์ด ํ•จ์ˆ˜์—์„œ ์ž„์‹œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์€ ์“ธ๋ชจ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ž„์‹œ ๊ฐ์ฒด๋Š” ๋ฒ”์œ„๋ฅผ ๋ฒ—์–ด๋‚˜๋ฉด ์ค„ ๋์—์„œ ์‚ญ์ œ๋ฉ๋‹ˆ๋‹ค.

์˜คํžˆ๋ ค ์ด๋™ ์˜๋ฏธ๋ก ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ž„์‹œ ๊ฐ์ฒด๋ฅผ โ€œ์•ฝํƒˆโ€ํ•˜๊ณ 

 Object& Object::operator+ (Object&& rhs) {
     // logic to modify rhs directly
     return rhs;
 }

๋ถˆํ•„์š”ํ•˜๊ฒŒ ๊นŠ์€ ์‚ฌ๋ณธ์ด ๋งŒ๋“ค์–ด์ง€์ง€ ์•Š๋„๋กํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ์ฐธ์กฐํ•˜๋ฉด ๋”ฅ ์นดํ”ผ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ์œ ์ผํ•œ ๋ถ€๋ถ„์€ ์ด์ œ E + F์ž…๋‹ˆ๋‹ค. ๋‚˜๋จธ์ง€๋Š” ์ด๋™ ์˜๋ฏธ๋ก ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๊ฒฐ๊ณผ๋ฅผ A์— ํ• ๋‹นํ•˜๋ ค๋ฉด ์ด๋™ ์ƒ์„ฑ์ž ๋˜๋Š” ํ• ๋‹น ์—ฐ์‚ฐ์ž๋„ ๊ตฌํ˜„ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.


๋‹ต๋ณ€

โ€œ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?โ€ ๊ทธ๋ฆฌ๊ณ  โ€œ๊ทธ๊ฒƒ์€ ๋ฌด์—‡์„ํ•ฉ๋‹ˆ๊นŒ?โ€ ์œ„์—์„œ ์„ค๋ช…ํ–ˆ์Šต๋‹ˆ๋‹ค.

โ€œ์‚ฌ์šฉํ•ด์•ผ ํ•  ๋•Œโ€์— ๋Œ€ํ•œ ์˜ˆ๋ฅผ ๋“ค๊ฒ ์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ํฐ ๋ฐฐ์—ด๊ณผ ๊ฐ™์€ ๋งŽ์€ ๋ฆฌ์†Œ์Šค๊ฐ€์žˆ๋Š” ํด๋ž˜์Šค๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

class ResHeavy{ //  ResHeavy means heavy resource
    public:
        ResHeavy(int len=10):_upInt(new int[len]),_len(len){
            cout<<"default ctor"<<endl;
        }

        ResHeavy(const ResHeavy& rhs):_upInt(new int[rhs._len]),_len(rhs._len){
            cout<<"copy ctor"<<endl;
        }

        ResHeavy& operator=(const ResHeavy& rhs){
            _upInt.reset(new int[rhs._len]);
            _len = rhs._len;
            cout<<"operator= ctor"<<endl;
        }

        ResHeavy(ResHeavy&& rhs){
            _upInt = std::move(rhs._upInt);
            _len = rhs._len;
            rhs._len = 0;
            cout<<"move ctor"<<endl;
        }

    // check array valid
    bool is_up_valid(){
        return _upInt != nullptr;
    }

    private:
        std::unique_ptr<int[]> _upInt; // heavy array resource
        int _len; // length of int array
};

ํ…Œ์ŠคํŠธ ์ฝ”๋“œ :

void test_std_move2(){
    ResHeavy rh; // only one int[]
    // operator rh

    // after some operator of rh, it becomes no-use
    // transform it to other object
    ResHeavy rh2 = std::move(rh); // rh becomes invalid

    // show rh, rh2 it valid
    if(rh.is_up_valid())
        cout<<"rh valid"<<endl;
    else
        cout<<"rh invalid"<<endl;

    if(rh2.is_up_valid())
        cout<<"rh2 valid"<<endl;
    else
        cout<<"rh2 invalid"<<endl;

    // new ResHeavy object, created by copy ctor
    ResHeavy rh3(rh2);  // two copy of int[]

    if(rh3.is_up_valid())
        cout<<"rh3 valid"<<endl;
    else
        cout<<"rh3 invalid"<<endl;
}

์•„๋ž˜์™€ ๊ฐ™์ด ์ถœ๋ ฅ :

default ctor
move ctor
rh invalid
rh2 valid
copy ctor
rh3 valid

์šฐ๋ฆฌ๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค std::move์œผ๋กœ move constructor๋งŒ๋“ ๋‹ค ์‰ฝ๊ฒŒ ์ž์›์„ ๋ณ€ํ™˜.

๋‹ค๋ฅธ std::move์œ ์šฉํ•œ ๊ณณ์ด ์žˆ์Šต๋‹ˆ๊นŒ?

std::move์š”์†Œ ๋ฐฐ์—ด์„ ์ •๋ ฌ ํ•  ๋•Œ๋„ ์œ ์šฉ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์„ ํƒ ์ •๋ ฌ ๋ฐ ๋ฒ„๋ธ” ์ •๋ ฌ๊ณผ ๊ฐ™์€ ๋งŽ์€ ์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ์š”์†Œ ์Œ์„ ๊ต์ฒดํ•˜์—ฌ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ์ด์ „์—๋Š” ์Šค์™€ํ•‘์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ์นดํ”ผ ์‹œ๋งจํ‹ฑ์— ์˜์ง€ํ•ด์•ผํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด์ œ๋ณด๋‹ค ํšจ์œจ์ ์ธ ์ด๋™ ์˜๋ฏธ๋ก ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•˜๋‚˜์˜ ์Šค๋งˆํŠธ ํฌ์ธํ„ฐ๋กœ ๊ด€๋ฆฌ๋˜๋Š” ์ปจํ…์ธ ๋ฅผ ๋‹ค๋ฅธ ์Šค๋งˆํŠธ ํฌ์ธํ„ฐ๋กœ ์˜ฎ๊ธฐ๋ ค๋Š” ๊ฒฝ์šฐ์—๋„ ์œ ์šฉ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ธ์šฉ :


๋‹ต๋ณ€

๋‹ค์Œ์€ (๊ฐ„๋‹จํ•œ) ์‚ฌ์šฉ์ž ์ •์˜ ๋ฒกํ„ฐ์— std :: move๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ „์ฒด ์˜ˆ์ž…๋‹ˆ๋‹ค.

์˜ˆ์ƒ ์ถœ๋ ฅ :

 c: [10][11]
 copy ctor called
 copy of c: [10][11]
 move ctor called
 moved c: [10][11]

๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ปดํŒŒ์ผํ•˜์‹ญ์‹œ์˜ค.

  g++ -std=c++2a -O2 -Wall -pedantic foo.cpp

์•”ํ˜ธ:

#include <iostream>
#include <algorithm>

template<class T> class MyVector {
private:
    T *data;
    size_t maxlen;
    size_t currlen;
public:
    MyVector<T> () : data (nullptr), maxlen(0), currlen(0) { }
    MyVector<T> (int maxlen) : data (new T [maxlen]), maxlen(maxlen), currlen(0) { }

    MyVector<T> (const MyVector& o) {
        std::cout << "copy ctor called" << std::endl;
        data = new T [o.maxlen];
        maxlen = o.maxlen;
        currlen = o.currlen;
        std::copy(o.data, o.data + o.maxlen, data);
    }

    MyVector<T> (const MyVector<T>&& o) {
        std::cout << "move ctor called" << std::endl;
        data = o.data;
        maxlen = o.maxlen;
        currlen = o.currlen;
    }

    void push_back (const T& i) {
        if (currlen >= maxlen) {
            maxlen *= 2;
            auto newdata = new T [maxlen];
            std::copy(data, data + currlen, newdata);
            if (data) {
                delete[] data;
            }
            data = newdata;
        }
        data[currlen++] = i;
    }

    friend std::ostream& operator<<(std::ostream &os, const MyVector<T>& o) {
        auto s = o.data;
        auto e = o.data + o.currlen;;
        while (s < e) {
            os << "[" << *s << "]";
            s++;
        }
        return os;
    }
};

int main() {
    auto c = new MyVector<int>(1);
    c->push_back(10);
    c->push_back(11);
    std::cout << "c: " << *c << std::endl;
    auto d = *c;
    std::cout << "copy of c: " << d << std::endl;
    auto e = std::move(*c);
    delete c;
    std::cout << "moved c: " << e << std::endl;
}