C++/Library 2021. 3. 24. 10:45

std::move

  • <utility> 라이브러리

  • 인자로 들어온 값을 R-value로 리턴해준다.


예제

  • std::move를 사용하지 않은 예제

    main.cpp

    #include <iostream>
    #include "Resource.h"
    #include "AutoPtr.h"
    using namespace std;
    
    int            main()
    {
      AutoPtr<Resource> res1(new Resource(10000000));
    
      cout << res1.ptr_ << endl;
    
      AutoPtr<Resource> res2 = res1;
    
      cout << res1.ptr_ << endl;
      cout << res2.ptr_ << endl;
    }
    
    /* stdout stderr
    Resource length constructed
    AutoPtr default constructor
    0158E360
    AutoPtr copy constructor
    Resource default constructed
    Resource copy assignment
    0158E360
    0158E408
    AutoPtr destructor
    Resource destoryed
    AutoPtr destructor
    Resource destoryed
    */

    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)
        : ptr_(a.ptr_)
      {
        std::cout << "AutoPtr copy constructor\n";
        ptr_ = new T;
        *ptr_ = *a.ptr_;
      }
    
      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 = (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; 
      }
    
      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;
      }
    };

  • 위의 코드에서 main.cpp<utility> 라이브러리를 include 하고, std::move를 사용하면 다음과 같다.

    main.cpp

    #include <iostream>
    #include <utility>
    #include "Resource.h"
    #include "AutoPtr.h"
    using namespace std;
    
    int            main()
    {
      AutoPtr<Resource> res1(new Resource(10000000));
    
      cout << res1.ptr_ << endl;
    
      AutoPtr<Resource> res2 = std::move(res1);
    
      cout << res1.ptr_ << endl;
      cout << res2.ptr_ << endl;
    }
    
    /* stdout stderr
    Resource length constructed
    AutoPtr default constructor
    00CADF50
    AutoPtr move constructor
    00000000
    00CADF50
    AutoPtr destructor
    Resource destoryed
    AutoPtr destructor
    */

Swap 예제

main.cpp

  #include <iostream>
  #include <utility>
  #include "Resource.h"
  #include "AutoPtr.h"
  using namespace std;

  template<typename T>
  void        MySwap(T& a, T& b)
  {
    T tmp{ std::move(a) };
    a = std::move(b);
    b = std::move(tmp);
  }

  int            main()
  {
    AutoPtr<Resource> res1(new Resource(3));
    res1->setAll(3);

    AutoPtr<Resource> res2(new Resource(5));
    res2->setAll(5);

    res1->print();
    res2->print();

    MySwap(res1, res2);

    res1->print();
    res2->print();
  }

  /* stdout stderr
  Resource length constructed
  AutoPtr default constructor
  Resource length constructed
  AutoPtr default constructor
  3 3 3
  5 5 5 5 5
  AutoPtr move constructor
  AutoPtr move assignment
  AutoPtr move assignment
  AutoPtr destructor
  5 5 5 5 5
  3 3 3
  AutoPtr destructor
  Resource destoryed
  AutoPtr destructor
  Resource destoryed
  */

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;
    }

    void    setAll(const int& v)
    {
      for (unsigned i = 0; i < length_; ++i)
        data_[i] = v;
    }
  };

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)
      : ptr_(a.ptr_)
    {
      std::cout << "AutoPtr copy constructor\n";
      ptr_ = new T;
      *ptr_ = *a.ptr_;
    }

    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 = (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; 
    }

    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;
    }

      T* operator->() const { return ptr_; }
  };

대부분의 라이브러리는 R-value에 대해서도 정의가 되어있다.

  #include <iostream>
  #include <utility>
  #include <vector>
  using namespace std;

  int            main()
  {
    vector<string> v;
    string str = "Hello";

    v.push_back(str);

    cout << str << endl;
    cout << v[0] << endl;

    v.push_back(std::move(str));

    cout << str << endl;
    cout << v[0] << ' ' << v[1] << endl;
  }

  /* stdout stderr
  Hello
  Hello

  Hello Hello
  */

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

C++ shared_ptr  (0) 2021.03.24
C++ unique_ptr  (0) 2021.03.24
C++ 출력 스트림 끊기  (0) 2021.03.24
C++ std::exception  (0) 2021.03.22
C++ reference_wrapper  (0) 2021.03.21