C++ 이동 생성자와 이동 대입 (Move Constructor and Move Assignment)

2021. 3. 24. 10:44·C++/SmartPointer

이동 생성자와 이동 대입 (Move Constructor and Move Assignment)

속도 비교

  • L-value 레퍼런스와 R-value 레퍼런스의 성능 차이가 꽤 존재한다.

    • R-value 레퍼런스의 경우 Deep Copy를 하지 않기 때문이다.

    • 생성자, 소멸자를 호출하는 부분이 강의와 살짝 달랐는데, 강의는 Release 모드여서 Debug 모드에 비해 단계가 줄어있는 상태여서 그랬다.

      • 나도 x86버전의 Release모드로 컴파일했더니 실행 파일이 없다는 LNK1104 에러가 발생하였다.

      • 백신 문제였는데, x64로 컴파일하니 실행에 문제는 없었다. 이유는 모르겠다.

      • 아래는 Debug 모드로 실행했다.

  • L-value 레퍼런스를 사용한 예제

    • Copy Constructor, Copy Assignment를 이용해 값을 Deep Copy한다.

    main.cpp

    #include <iostream>
    #include "Resource.h"
    #include "AutoPtr.h"
    #include "Timer.h"
    
    using namespace std;
    
    AutoPtr<Resource> generateResource()
    {
      AutoPtr<Resource> res(new Resource(10000000));
    
      return res;
    }
    
    int            main()
    {
      Timer timer;
      {
        AutoPtr<Resource> main_res;
        main_res = generateResource();
      }
      timer.elapsed();
    }
    
    /* stdout stderr
    AutoPtr default constructor
    Resource length constructed
    AutoPtr default constructor
    AutoPtr copy constructor
    Resource default constructed
    Resource copy assignment
    AutoPtr destructor
    Resource destoryed
    AutoPtr copy assignment
    Resource default constructed
    Resource copy assignment
    AutoPtr destructor
    Resource destoryed
    AutoPtr destructor
    Resource destoryed
    0.0771911
    */

    Resource.h

    #pragma once
    
    #include <iostream>
    
    class Resource
    {
    public:
      int    *data_ = nullptr;
      unsigned length_ = 0;
    
      Resource()
      {
        std::cout << "Resource default constructed\n";
      }
    
      Resource(unsigned length)
      {
        std::cout << "Resource length constructed\n";
        init(length);
      }
    
      Resource(const Resource& res)
      {
        std::cout << "Resource copy constructed\n";
        init(res.length_);
        for (unsigned i = 0; i < length_; ++i)
          data_[i] = res.data_[i];
      }
    
      ~Resource()
      {
        std::cout << "Resource destoryed\n";
    
        if (data_ != nullptr) delete[] data_;
      }
    
      void    init(unsigned length)
      {
        data_ = new int[length];
        length_ = length;
      }
    
      Resource& operator = (Resource& res)
      {
        std::cout << "Resource copy assignment\n";
        if (&res == this) return *this;
    
        if (data_ != nullptr) delete[] data_;
        init(res.length_);
        for (unsigned i = 0; i < length_; ++i)
          data_[i] = res.data_[i];
        return *this;
      }
    
      void print()
      {
        for (unsigned i = 0; i < length_; ++i)
          std::cout << data_[i] << ' ';
        std::cout << std::endl;
      }
    };

    AutoPtr.h

    #pragma once
    
    #include <iostream>
    
    template<class T>
    class AutoPtr
    {
    public:
      T* ptr_;
    
      AutoPtr(T *ptr = nullptr)
        : ptr_(ptr)
      {
        std::cout << "AutoPtr default constructor\n";
      }
    
      AutoPtr(const AutoPtr& a)
      {
        std::cout << "AutoPtr copy constructor\n";
        ptr_ = new T;
        *ptr_ = *a.ptr_;
      }
    
      ~AutoPtr()
      {
        std::cout << "AutoPtr destructor\n";
        if (ptr_ != nullptr) delete ptr_;
      }
    
      AutoPtr& operator = (const AutoPtr& a)
      {
        std::cout << "AutoPtr copy assignment\n";
        if (&a == this)
          return *this;
    
        if (ptr_ != nullptr) delete ptr_;
    
        ptr_ = new T;
        *ptr_ = *a.ptr_;
        return *this;
      }
    };

    Timer.h

    #pragma once
    
    #include <iostream>
    #include <chrono>
    
    class Timer
    {
        using clock_t = std::chrono::high_resolution_clock;
        using second_t = std::chrono::duration<double, std::ratio<1>>;
    
        std::chrono::time_point<clock_t> start_time = clock_t::now();
    
    public:
        void elapsed()
        {
            std::chrono::time_point<clock_t> end_time = clock_t::now();
    
            std::cout << std::chrono::duration_cast<second_t>(end_time - start_time).count() << std::endl;
        }
    };

  • R-value 레퍼런스를 사용한 예제

    • AutoPtr 클래스에서 Move Constructor, Move Assignment를 이용했다.

    main.cpp

    #include <iostream>
    #include "Resource.h"
    #include "AutoPtr.h"
    #include "Timer.h"
    
    using namespace std;
    
    AutoPtr<Resource> generateResource()
    {
      AutoPtr<Resource> res(new Resource(10000000));
    
      return res;
    }
    
    int            main()
    {
      Timer timer;
      {
        AutoPtr<Resource> main_res;
        main_res = generateResource();
      }
    
      timer.elapsed();
    }
    
    /* stdout stderr
    AutoPtr default constructor
    Resource length constructed
    AutoPtr default constructor
    AutoPtr move constructor
    AutoPtr destructor
    AutoPtr move assignment
    AutoPtr destructor
    AutoPtr destructor
    Resource destoryed
    0.0090543
    */

    Resource.h

    #pragma once
    
    #include <iostream>
    
    class Resource
    {
    public:
      int    *data_ = nullptr;
      unsigned length_ = 0;
    
      Resource()
      {
        std::cout << "Resource default constructed\n";
      }
    
      Resource(unsigned length)
      {
        std::cout << "Resource length constructed\n";
        init(length);
      }
    
      Resource(const Resource& res)
      {
        std::cout << "Resource copy constructed\n";
        init(res.length_);
        for (unsigned i = 0; i < length_; ++i)
          data_[i] = res.data_[i];
      }
    
      ~Resource()
      {
        std::cout << "Resource destoryed\n";
    
        if (data_ != nullptr) delete[] data_;
      }
    
      void    init(unsigned length)
      {
        data_ = new int[length];
        length_ = length;
      }
    
      Resource& operator = (Resource& res)
      {
        std::cout << "Resource copy assignment\n";
        if (&res == this) return *this;
    
        if (data_ != nullptr) delete[] data_;
        init(res.length_);
        for (unsigned i = 0; i < length_; ++i)
          data_[i] = res.data_[i];
        return *this;
      }
    
      void print()
      {
        for (unsigned i = 0; i < length_; ++i)
          std::cout << data_[i] << ' ';
        std::cout << std::endl;
      }
    };

    AutoPtr.h

    #pragma once
    
    #include <iostream>
    
    template<class T>
    class AutoPtr
    {
    public:
      T* ptr_;
    
      AutoPtr(T *ptr = nullptr)
        : ptr_(ptr)
      {
        std::cout << "AutoPtr default constructor\n";
      }
    
      AutoPtr(AutoPtr&& a)
        : ptr_(a.ptr_)
      {
        std::cout << "AutoPtr move constructor\n";
        a.ptr_ = nullptr;
      }
    
      ~AutoPtr()
      {
        std::cout << "AutoPtr destructor\n";
        if (ptr_ != nullptr) delete ptr_;
      }
    
      AutoPtr& operator = (AutoPtr&& a)
      {
        std::cout << "AutoPtr move assignment\n";
        if (&a == this)
          return *this;
    
        if (ptr_ != nullptr) delete ptr_;
    
        ptr_ = a.ptr_;
        a.ptr_ = nullptr;
        return *this;
      }
    };

    Timer.h

    #pragma once
    
    #include <iostream>
    #include <chrono>
    
    class Timer
    {
        using clock_t = std::chrono::high_resolution_clock;
        using second_t = std::chrono::duration<double, std::ratio<1>>;
    
        std::chrono::time_point<clock_t> start_time = clock_t::now();
    
    public:
        void elapsed()
        {
            std::chrono::time_point<clock_t> end_time = clock_t::now();
    
            std::cout << std::chrono::duration_cast<second_t>(end_time - start_time).count() << std::endl;
        }
    };
  • 보다 정확한 시간을 측정하려면 출력 하지 않은 채로 시간을 재면 된다.

저작자표시 (새창열림)

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

C++ 순환 의존성 문제 (Circular Dependency Issues)  (0) 2021.03.24
C++ R-value Reference  (0) 2021.03.24
C++ Syntax vs Semantics  (0) 2021.03.24
C++ 스마트 포인터 (Smart Pointer)  (0) 2021.03.22
'C++/SmartPointer' 카테고리의 다른 글
  • C++ 순환 의존성 문제 (Circular Dependency Issues)
  • C++ R-value Reference
  • C++ Syntax vs Semantics
  • C++ 스마트 포인터 (Smart Pointer)
Caniro
Caniro
  • Caniro
    Minimalism
    Caniro
  • 전체
    오늘
    어제
    • 분류 전체보기 (317) N
      • Algorithm (13)
        • 알기 쉬운 알고리즘 (10)
        • Search (1)
        • Sort (2)
      • Arduino (0)
      • C++ (185)
        • Class (46)
        • Exception (6)
        • Library (51)
        • Overloading (10)
        • SmartPointer (5)
        • Syntax (33)
        • TBC++ (23)
        • Templates (9)
        • VisualStudio (2)
      • Embedded (1)
      • Git (4)
      • Java (5)
      • Linux (16)
        • Error (1)
        • Linux Structure (11)
      • MacOS (7)
      • OS (1)
        • Concurrency (1)
      • Python (21)
        • Class (1)
        • Function (2)
        • Syntax (17)
      • Raspberrypi (9)
      • Review (1)
      • Utility (12)
        • VSCode (5)
        • VirtualBox (3)
      • Web (8)
        • Nginx (1)
        • React (3)
        • Django (1)
      • Windows (20) N
        • Registry (3)
        • WSL (1)
        • DeviceDriver (6)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    KakaoTalk
    시스템 복구
    윈도우
    윈도우 명령어
    spring
    Solaris 10
    SFC
    vscode
    mspaint
    MacOS
    citrix workspace
    dism
    java
    EXCLUDE
    windows
    Workspace
    Windows 11
    알림
    logi options
    스프링
    SunOS 5.1
    그림판
    unix
    백기선
    맥북 카카오톡 알림 안뜸
    스프링 프레임워크 핵심 기술
    로지텍 마우스 제스처
    제외
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
Caniro
C++ 이동 생성자와 이동 대입 (Move Constructor and Move Assignment)
상단으로

티스토리툴바