[C++] C++의 Move semantics, forwarding

2026. 2. 27. 23:00·C++/Study

서론

C++11 이후 현대적 C++ 설계의 중심에는 항상 성능과 자원 관리가 있다. 그 핵심 도구가 바로 std::move와 std::forward다.

우리의 교과서 모던 C++에서 이 move와 forward에 대한 중요성을 잘 다루고있다. 오늘은 이 두 함수가 왜 존재하며, 내부적으로는 어떤 원리로 동작하는지, 주로 하는 실수에 대해 정리해보자.

Modern C++ Chapter.5 참조

값 카테고리(Value Category): lvalue와 rvalue의 본질

move와 forward를 논하기 전에 반드시 짚고 넘어가야 할 것이 값 카테고리다. 단순히 "이름이 있으면 lvalue, 없으면 rvalue"라는 식의 암기보다 수명(Lifetime)과 정체성(Identity) 관점에서 접근하는 것이 정확하다.

  • lvalue (left value): 지속적인 메모리 위치를 가지며, 이름이 있어 다시 참조할 수 있는 값. (예: 변수, 역참조된 포인터)
  • rvalue (right value): 표현식이 끝나면 사라지는 임시적인 값. (예: 리터럴, 함수가 반환한 임시 객체)

C++11은 여기에 rvalue reference(&&)를 도입하여, 수명이 다해가는 객체의 자원을 안전하게 "훔쳐올(Steal)" 수 있는 길을 열어주었다.

move semantics

복사 비용이 큰 std::vector나 std::string을 다룰 때, 원본 데이터가 더 이상 필요 없다면 굳이 데이터를 새로 할당하고 내용을 복사할 필요가 없다. 원본이 가진 데이터 포인터만 슥 바꿔치기하면 끝난다. 이것이 이동 의미론(move semantics)의 핵심이다.

std::vector<int> source = {1, 2, 3, 4, 5};
std::vector<int> target = std::move(source); 
// source의 포인터를 target이 가져가고, source는 비워진다.

이 과정에서 가장 중요한 점은 원본 객체를 유효하지만 상태를 알 수 없는(valid but unspecified) 상태로 만드는 것이다.

std::move의 정체: 이동이 아니라 '의도'의 캐스팅

많은 이들이 오해하는 지점이 std::move를 호출하면 그 즉시 데이터가 이동한다고 생각하는 것이다. 하지만 std::move 자체는 아무것도 이동시키지 않는다.

std::move는 전달받은 인자를 무조건 rvalue reference로 변환하는 컴파일 타임 캐스팅 도구일 뿐이다.

template <typename T>
typename std::remove_reference<T>::type&& move(T&& t) noexcept {
    return static_cast<typename std::remove_reference<T>::type&&>(t);
}

결국 std::move는 컴파일러에게 "이 객체는 이제 곧 사라질 녀석(또는 더 이상 안 쓸 녀석)이니, 이동 생성자를 호출해도 안전해!"라고 알려주는 명시적인 의도 표현이다.

std::forward와 Perfect Forwarding: 값의 성격 그대로 전달하기

std::forward는 주로 템플릿 함수에서 인자를 다른 함수로 넘길 때 사용한다. 템플릿 매개변수 T&&(Forwarding Reference)로 인자를 받으면, 함수 내부에서 해당 인자는 이름이 있는 변수가 되어 항상 lvalue가 된다.

이때 호출자가 원래 넘겨줬던 성질(lvalue였는지, rvalue였는지)을 그대로 유지해서 다음 함수에 전달하는 기법을 완벽한 전달(Perfect Forwarding)이라고 한다.

template <typename T>
void Wrapper(T&& arg) {
    // std::forward는 T의 타입 정보를 보고 
    // lvalue는 lvalue로, rvalue는 rvalue로 캐스팅해준다.
    TargetFunction(std::forward<T>(arg));
}

흔히 발생하는 실수와 안티패턴

1. 반환 값에 std::move 붙이기

std::string GetName() {
    std::string name = "돼지표";
    return std::move(name); // [비권장] RVO(Return Value Optimization)를 방해한다.
}

최신 컴파일러는 return name; 만으로도 최적의 효율을 낸다. move를 억지로 붙이면 오히려 컴파일러의 최적화를 가로막는 꼴이 된다.

2. 이동 후 객체 사용

#include <iostream>
#include <string>

int main() {
    std::string original = "Hello World";

    std::string moved = std::move(original);

    // 이동 후 original 사용
    std::cout << "original: " << original << std::endl; // ⚠️ 값이 비어있을 가능성 높음
    std::cout << "moved: " << moved << std::endl;

    if (!original.empty()) {  // ⚠️ 논리 에러 가능
        std::cout << "original still has data!\n";
    }

    return 0;
}

std::move 이후의 객체는 '빈 껍데기'일 가능성이 높다. 이를 다시 사용하는 코드는 예기치 못한 크래시나 논리 에러를 유발한다.

3. const 객체에 대한 std::move

#include <iostream>
#include <string>

int main() {
    const std::string str = "Hello";

    std::string moved = std::move(str); // ❗ 이동 아님, 복사 발생

    std::cout << moved << std::endl;

    return 0;
}

const객체는 rvalue로 캐스팅되더라도 이동 생성자가 아닌 복사 생성자가 호출된다. 자원을 훔쳐오려면 원본을 수정할 수 있어야 하기 때문이다.

'C++ > Study' 카테고리의 다른 글

[C++] C++의 Rule of 3/5/0  (0) 2026.03.01
[C++] C++의 다양한 컨테이너들  (2) 2025.07.17
'C++/Study' 카테고리의 다른 글
  • [C++] C++의 Rule of 3/5/0
  • [C++] C++의 다양한 컨테이너들
돼지표
돼지표
https://github.com/wkdgns135
  • 돼지표
    돼지표 개발 스토리
    돼지표
  • 전체
    오늘
    어제
    • 분류 전체보기 (117)
      • C++ (62)
        • Coding Test (53)
        • Study (3)
      • Python (1)
      • Machine Learning (2)
      • Computer Graphics (4)
        • Curly Hair Simulation (2)
      • GPU Programming (11)
        • CUDA basic (7)
        • CUDA fluidsGL (4)
      • Unreal 5 (27)
        • Troubleshooting (4)
        • FPS Shooting (5)
        • Study (11)
        • EOS (1)
        • STILL LOADING (5)
      • Computer Science (9)
        • Algorithm (4)
      • Other (1)
  • 블로그 메뉴

    • 글쓰기
  • 링크

    • Github
  • 공지사항

  • 인기 글

  • 태그

    dp
    STILL LOADING
    Rendering Pipeline
    C++
    BFS
    OpenGL
    Algorithm
    CUDA
    정렬
    unreal 5
    그래프 탐색
    자료 구조
    FPS
    구현
    GPU Programming
    아이작 맵 생성
    Fluid Simulation
    수학
    CS
    UE5
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
돼지표
[C++] C++의 Move semantics, forwarding
상단으로

티스토리툴바