Movable but Non-Copyable Types

| Home | Libraries | People | FAQ | More

## Movable but Non-Copyable Types

Some types are not amenable to copy semantics but can still be made movable. For example:

- `unique_ptr` (non-shared, non-copyable ownership)
- A type representing a thread of execution
- A type representing a file descriptor

By making such types movable (though still non-copyable) their utility is tremendously increased. Movable but non-copyable types can be returned by value from factory functions:

    file_descriptor create_file(/* ... */);
    //...
    file_descriptor data_file;
    //...
    data_file = create_file(/* ... */);  // No copies!

In the above example, the underlying file handle is passed from object to object, as long as the source `file_descriptor` is a rvalue. At all times, there is still only one underlying file handle, and only one `file_descriptor` owns it at a time.

To write a movable but not copyable type in portable syntax, you need to follow these simple steps:

- Put the following macro in the private section: `BOOST_MOVABLE_BUT_NOT_COPYABLE(classname)`
- Write a move constructor and a move assignment taking the parameter as `BOOST_RV_REF(classname)`

Here's the definition of `file descriptor` using portable syntax:

    #include <boost/move/utility_core.hpp>
    #include <stdexcept>

    class file_descriptor
    {
       int os_descr_;

       private:
       BOOST_MOVABLE_BUT_NOT_COPYABLE(file_descriptor)

       public:
       explicit file_descriptor(const char *filename)              //Constructor
          : os_descr_(operating_system_open_file(filename))
       {  if(!os_descr_) throw std::runtime_error("file not found");  }

       ~file_descriptor()                                          //Destructor
       {  if(os_descr_)  operating_system_close_file(os_descr_);  }

       file_descriptor(BOOST_RV_REF(file_descriptor) x)            // Move ctor
          :  os_descr_(x.os_descr_)
       {  x.os_descr_ = 0;  }

       file_descriptor& operator=(BOOST_RV_REF(file_descriptor) x) // Move assign
       {
          if(os_descr_) operating_system_close_file(os_descr_);
          os_descr_   = x.os_descr_;
          x.os_descr_ = 0;
          return *this;
       }

       bool empty() const   {  return os_descr_ == 0;  }
    };