ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [C++] std::move return은 정말 필요할까?
    쾌락없는 책임 (공부)/C++ 짜잘이 2023. 1. 22. 11:41
    반응형

    개요

    C++11부터의 중요 화두인 R-value reference를 보고 나서 '앞으로 모든 return 에 std::move를 명시해야 하는가?' 란 의문이 생기게 되었습니다. 앞으로 기존에 단순 return 하는 함수들에도 이를 써야 하나 라는 생각을 했는데 이번에 이에 대해서 알아본 결과를 한번 적어보겠습니다.

     

     

    일단 return std::move() 는 불필요하다

    일단 알아본 바로는 move로 반환할 이유가 없다는 것입니다.

     

    먼저 일반적으로 반환하는 경우 컴파일러가 자동적으로 R-value로 변경을 해 줘서 이후 함수 반환값을 통해서 이동 생성자를 부를 수 있다고 합니다. 다만 std::move를 활용하게 되면 컴파일러가 이를 최적화할 여지가 사라진다고 합니다.

     

     

    RVO, NRVO와 copy elision

    RVO 는 Return Value Optimization
    NRVO는 Named Return Value Optimization
    elision은 생략

    위 return move와 관련한 부분을 알아보면 이런 개념들이 나오게 됩니다. 컴파일러가 알아서 반환값에 대한 최적화를 하는 것인데요. 이러한 개념으로 인해서 컴파일러가 반환값을 r-value로 반환을 해주게 되면서 move를 명시해 줄 필요가 없다는 것입니다.

     

    이 경우를 제가 비주얼 스튜디오에서 한번 확인을 해 봤습니다.

    #include <iostream>
    
    struct Foo
    {
        Foo() { std::cout << "Constructed" << std::endl; }
        Foo(const Foo&) { std::cout << "Copy-constructed" << std::endl; }
        Foo(Foo&&) { std::cout << "Move-constructed" << std::endl; }
        ~Foo() { std::cout << "Destructed" << std::endl; }
    };
    
    Foo Func()
    {
        Foo f;
        std::cout << &f << '\n';
        return f;
    }
    
    int main()
    {
        Foo f1{ Func() };
        std::cout << &f1 << '\n';
        return 0;
    }

    여러가지 장난을 쳐본 결과 일단 Debug 모드에서는 move constructor가 불렸습니다. Release 모드에서는 이와 관련한 RVO, NRVO가 켜져 있다고 했는데 이 덕분인지 Foo에서는 Constructored, Destructored만 불리게 되었습니다.

    이게 Debug 모드.

    보시는 것처럼 Debug 모드에서는 주소값도 다른 모습을 볼 수 있는데

    요건 Release 모드

    Release 모드에서는 최적화를 해줘서 주소값도 그렇고 한결 간결한 모습을 볼 수 있습니다.

     

    그럼 이번 의문인 std::move를 적용하면 어떻게 될까요?

    Foo Func()
    {
        Foo f;
        std::cout << &f << '\n';
        return std::move(f);
    }

    Debug
    Release

    둘 다 뭔가 이상한 모습을 볼 수 있습니다. 이 경우 이동 생성자를 통해서 모두 처리되는 모습을 볼 수 있습니다. 결국 RVO / NRVO 둘 다 일어나지 않은 모습을 볼 수 있습니다. 최신의 컴파일러일수록 이런 부분의 최적화는 제대로 이루어지고 있으며 함수 내 지역변수에 대해서 move를 해야 할 필요성이 점점 없습니다.

    당장 비주얼 2022 버전에서 돌려보면 저렇게 쓰지 말라는 경고가 나오는걸 볼 수 있습니다.

    반응형

    댓글

Designed by Tistory.