Procedura: Scrivere un costruttore di spostamento

In questo argomento viene descritto come scrivere un Sposta costruttore e un operatore di assegnazione di spostamento per una classe C++.Un costruttore di spostamento consente di implementare la semantica di spostamento, che consente di migliorare notevolmente le prestazioni delle applicazioni.Per ulteriori informazioni sulla semantica di spostamento, vedere Dichiarazione di riferimento Rvalue: &&.

In questo argomento si basa la seguente classe di C++, MemoryBlock, che gestisce un buffer di memoria.

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

Le procedure seguenti viene descritto come scrivere un costruttore di spostamento e un operatore di assegnazione di spostamento per l'esempio di classe C++.

Per creare un costruttore di spostamento per una classe C++

  1. Definire un metodo di costruttore vuoto che accetta un riferimento a un rvalue per il tipo di classe come parametro, come illustrato nell'esempio riportato di seguito:

    MemoryBlock(MemoryBlock&& other)
       : _data(NULL)
       , _length(0)
    {
    }
    
  2. Nel costruttore di spostamento, assegnare i membri dati della classe dall'oggetto di origine per l'oggetto in fase di costruzione:

    _data = other._data;
    _length = other._length;
    
  3. Assegnare i membri dati dell'oggetto di origine per i valori predefiniti.Impedisce il distruttore di liberazione di risorse (ad esempio la memoria) più volte:

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

Per creare un operatore di assegnazione di spostamento per una classe C++

  1. Definire un operatore di assegnazione vuoti che accetta un riferimento a un rvalue per il tipo di classe come parametro e restituisce un riferimento al tipo di classe, come illustrato nell'esempio riportato di seguito:

    MemoryBlock& operator=(MemoryBlock&& other)
    {
    }
    
  2. L'operatore di assegnazione di spostamento, aggiungere un'istruzione condizionale che non esegue alcuna operazione se si tenta di assegnare l'oggetto a se stesso.

    if (this != &other)
    {
    }
    
  3. Nell'istruzione condizionale, liberare le risorse (ad esempio la memoria) dall'oggetto assegnato a.

    Nell'esempio riportato di seguito consente di liberare i _data membro dell'oggetto assegnato a:

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

    Seguire i passaggi 2 e 3 nella prima procedura per trasferire i membri dati dall'oggetto di origine per l'oggetto in fase di costruzione:

    // 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. Restituire un riferimento all'oggetto corrente, come illustrato nell'esempio riportato di seguito:

    return *this;
    

Esempio

Nell'esempio riportato di seguito viene illustrato il completo spostarsi costruttore e operatore di assegnazione per la MemoryBlock classe:

// Move constructor.
MemoryBlock(MemoryBlock&& other)
   : _data(NULL)
   , _length(0)
{
   std::cout << "In MemoryBlock(MemoryBlock&&). length = " 
             << other._length << ". Moving resource." << std::endl;

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

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

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

      // 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;
   }
   return *this;
}

Nell'esempio riportato di seguito viene illustrato come la semantica di spostamento può migliorare le prestazioni delle applicazioni.L'esempio aggiunge due elementi a un oggetto vettoriale e quindi viene inserito un nuovo elemento tra i due elementi esistenti.In Visual C++ 2010, vector classe utilizza Sposta la semantica per eseguire l'operazione di inserimento in modo efficiente, spostando gli elementi del vettore invece di copiarli.

// rvalue-references-move-semantics.cpp
// compile with: /EHsc
#include "MemoryBlock.h"
#include <vector>

using namespace std;

int main()
{
   // Create a vector object and add a few elements to it.
   vector<MemoryBlock> v;
   v.push_back(MemoryBlock(25));
   v.push_back(MemoryBlock(75));

   // Insert a new element into the second position of the vector.
   v.insert(v.begin() + 1, MemoryBlock(50));
}

Questo esempio produce il seguente output:

In MemoryBlock(size_t). length = 25.
In MemoryBlock(MemoryBlock&&). length = 25. Moving resource.
In ~MemoryBlock(). length = 0.
In MemoryBlock(size_t). length = 75.
In MemoryBlock(MemoryBlock&&). length = 25. Moving resource.
In ~MemoryBlock(). length = 0.
In MemoryBlock(MemoryBlock&&). length = 75. Moving resource.
In ~MemoryBlock(). length = 0.
In MemoryBlock(size_t). length = 50.
In MemoryBlock(MemoryBlock&&). length = 50. Moving resource.
In MemoryBlock(MemoryBlock&&). length = 50. Moving resource.
In operator=(MemoryBlock&&). length = 75.
In operator=(MemoryBlock&&). length = 50.
In ~MemoryBlock(). length = 0.
In ~MemoryBlock(). length = 0.
In ~MemoryBlock(). length = 25. Deleting resource.
In ~MemoryBlock(). length = 50. Deleting resource.
In ~MemoryBlock(). length = 75. Deleting resource.

Prima di Visual C++ 2010, in questo esempio produce il seguente output:

In MemoryBlock(size_t). length = 25.
In MemoryBlock(const MemoryBlock&). length = 25. Copying resource.
In ~MemoryBlock(). length = 25. Deleting resource.
In MemoryBlock(size_t). length = 75.
In MemoryBlock(const MemoryBlock&). length = 25. Copying resource.
In ~MemoryBlock(). length = 25. Deleting resource.
In MemoryBlock(const MemoryBlock&). length = 75. Copying resource.
In ~MemoryBlock(). length = 75. Deleting resource.
In MemoryBlock(size_t). length = 50.
In MemoryBlock(const MemoryBlock&). length = 50. Copying resource.
In MemoryBlock(const MemoryBlock&). length = 50. Copying resource.
In operator=(const MemoryBlock&). length = 75. Copying resource.
In operator=(const MemoryBlock&). length = 50. Copying resource.
In ~MemoryBlock(). length = 50. Deleting resource.
In ~MemoryBlock(). length = 50. Deleting resource.
In ~MemoryBlock(). length = 25. Deleting resource.
In ~MemoryBlock(). length = 50. Deleting resource.
In ~MemoryBlock(). length = 75. Deleting resource.

La versione di questo esempio che utilizzi spostare la semantica è più efficiente rispetto alla versione che non utilizza la semantica di spostamento perché consente di eseguire un numero inferiore copia, allocazione di memoria e le operazioni di deallocazione di memoria.

Programmazione efficiente

Per evitare perdite di risorse, liberare sempre risorse (ad esempio memoria, handle di file e socket) nell'operatore di assegnazione di spostamento.

Per impedire la distruzione irreversibile delle risorse, di gestire correttamente self-assignment nell'operatore di assegnazione di spostamento.

Se si fornisce un costruttore di spostamento e un operatore di assegnazione di spostamento per la classe, è possibile eliminare il codice ridondante scrivendo il costruttore di spostamento per chiamare l'operatore di assegnazione di spostamento.Nell'esempio seguente viene illustrata una versione modificata del costruttore che chiama l'operatore di assegnazione spostamento spostamento:

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

Il std::move funzione consente di mantenere la proprietà rvalue del other parametro.

Vedere anche

Riferimenti

Dichiarazione di riferimento Rvalue: &&

Altre risorse

<utility> move