How to: Write a Move Constructor

This topic describes how to write a move constructor and a move assignment operator for a C++ class. A move constructor enables you to implement move semantics, which can significantly improve the performance of your applications. For more information about move semantics, see Rvalue Reference Declarator: &&.

This topic builds upon the following C++ class, MemoryBlock, which manages a memory buffer.

// MemoryBlock.h
#pragma once
#include <iostream>
#include <algorithm>

class MemoryBlock
{
public:

   // Simple constructor that initializes the resource.
   explicit MemoryBlock(size_t length)
      : _length(length)
      , _data(new int[length])
   {
      std::cout << "In MemoryBlock(size_t). length = "
                << _length << "." << std::endl;
   }

   // Destructor.
   ~MemoryBlock()
   {
      std::cout << "In ~MemoryBlock(). length = "
                << _length << ".";
      
      if (_data != NULL)
      {
         std::cout << " Deleting resource.";
         // Delete the resource.
         delete[] _data;
      }

      std::cout << std::endl;
   }

   // Copy constructor.
   MemoryBlock(const MemoryBlock& other)
      : _length(other._length)
      , _data(new int[other._length])
   {
      std::cout << "In MemoryBlock(const MemoryBlock&). length = " 
                << other._length << ". Copying resource." << std::endl;

      std::copy(other._data, other._data + _length, _data);
   }

   // Copy assignment operator.
   MemoryBlock& operator=(const MemoryBlock& other)
   {
      std::cout << "In operator=(const MemoryBlock&). length = " 
                << other._length << ". Copying resource." << std::endl;

      if (this != &other)
      {
         // Free the existing resource.
         delete[] _data;

         _length = other._length;
         _data = new int[_length];
         std::copy(other._data, other._data + _length, _data);
      }
      return *this;
   }

   // Retrieves the length of the data resource.
   size_t Length() const
   {
      return _length;
   }

private:
   size_t _length; // The length of the resource.
   int* _data; // The resource.
};

The following procedures describe how to write a move constructor and a move assignment operator for the example C++ class.

To create a move constructor for a C++ class

  1. Define an empty constructor method that takes an rvalue reference to the class type as its parameter, as demonstrated in the following example:

MemoryBlock(MemoryBlock&& other)
   : _data(NULL)
   , _length(0)
{
}

  2. In the move constructor, assign the class data members from the source object to the object that is being constructed:

_data = other._data;
_length = other._length;

  3. Assign the data members of the source object to default values. This prevents the destructor from freeing resources (such as memory) multiple times:

other._data = NULL;
other._length = 0;

To create a move assignment operator for a C++ class

  1. Define an empty assignment operator that takes an rvalue reference to the class type as its parameter and returns a reference to the class type, as demonstrated in the following example:

MemoryBlock& operator=(MemoryBlock&& other)
{
}

  2. In the move assignment operator, add a conditional statement that performs no operation if you try to assign the object to itself.

if (this != &other)
{
}

  3. In the conditional statement, free any resources (such as memory) from the object that is being assigned to. The following example frees the _data member from the object that is being assigned to:

// Free the existing resource.
delete[] _data;

  Follow steps 2 and 3 in the first procedure to transfer the data members from the source object to the object that is being constructed:

// Copy the data pointer and its length from the 
// source object.
_data = other._data;
_length = other._length;

// Release the data pointer from the source object so that
// the destructor does not free the memory multiple times.
other._data = NULL;
other._length = 0;

  4. Return a reference to the current object, as shown in the following example:

return *this;

To prevent resource leaks, always free resources (such as memory, file handles, and sockets) in the move assignment operator.

To prevent the unrecoverable destruction of resources, properly handle self-assignment in the move assignment operator.

If you provide both a move constructor and a move assignment operator for your class, you can eliminate redundant code by writing the move constructor to call the move assignment operator. The following example shows a revised version of the move constructor that calls the move assignment operator:

// Move constructor.
MemoryBlock(MemoryBlock&& other)
   : _data(NULL)
   , _length(0)
{
   *this = std::move(other);
}

posted @ 2013-10-21 22:46  avexer  阅读(408)  评论(0编辑  收藏  举报