Aracılığıyla paylaş


Nasıl yapılır: taşıma kurucu yazma

Bu konuda nasıl yazılacağı açıklanır bir yapıcı taşıma ve C++ sınıf için taşıma atama işleci. Taşıma yapıcı uygulamalarınızın performansını önemli ölçüde artırabilirsiniz taşıma semantiği uygulamak etkinleştirir. Taşıma semantiği hakkında daha fazla bilgi için bkz: Rvalue başvuru Bildiricisi: & &.

Bu konu aşağıdaki C++ sınıf oluşturur MemoryBlock, ara belleğe yönetir.

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

Aşağıdaki yordamlardan taşıma yapıcı ve taşıma atama işleci örneğin C++ sınıf yazma anlatıyor.

Taşıma yapıcı bir C++ sınıf oluşturmak için

  1. Aşağıdaki örnekte gösterildiği gibi parametre olarak bir sınıf türü rvalue başvuru alır bir boş bir yapıcı yöntemi tanımlar:

    MemoryBlock(MemoryBlock&& other)
       : _data(NULL)
       , _length(0)
    {
    }
    
  2. Taşıma kurucusunda sınıfı veri üyeleri kaynağı nesnesinden oluşturulmuyor nesneye atayın:

    _data = other._data;
    _length = other._length;
    
  3. Kaynak nesne veri üyeleri için varsayılan değerler atayın. Bu kaynakları (bellek gibi)'ı birden çok kez boşaltma yıkıcı engeller:

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

Taşıma atama işleci için C++ sınıf oluşturmak için

  1. Sınıf türü parametresi yarýçapý rvalue referansı alıp sınıf türü için bir başvuru verir boş atama işleci aşağıdaki örnekte gösterildiği gibi tanımlayın:

    MemoryBlock& operator=(MemoryBlock&& other)
    {
    }
    
  2. Taşıma atama işleci, nesnenin kendisine atamak çalışırsanız, işlem gerçekleştiren bir koşul deyimi ekleyin.

    if (this != &other)
    {
    }
    
  3. Koşullu deyiminde nesnesinden için atanan kaynakları (bellek gibi) serbest.

    Aşağıdaki örnek boşaltır _data için atanan nesnesinden üye:

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

    2 Ve 3 kaynağı nesnesinden veri üyeleri oluşturulmuyor nesnesine aktarmak için ilk yordamdaki adımları izleyin:

    // 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. Aşağıdaki örnekte gösterildiği gibi geçerli nesnesine bir başvuru döndürür:

    return *this;
    

Örnek

Tam yapıcı ve atama işleci için taşır aşağıdaki örnekte gösterilmektedir MemoryBlock sınıfı:

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

Aşağıdaki örnek, nasıl hareket semantiği uygulamalarınızın performansı gösterir. Örneğin, iki öğe bir vektör nesnesine ekler ve iki varolan öğeleri arasında yeni bir öğe ekler. De Visual C++ 2010, vector sınıfını kullanır hareket semantiği kopyalamak yerine vektör öğeleri taşıyarak verimli ekleme işlemi gerçekleştirmek için.

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

Bu örnek aşağıdaki çıktıyı üretir:

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.

Önce Visual C++ 2010, bu örnek aşağıdaki çıktıyı üretir:

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.

Bu örnek kullanır semantiği taşı taşıma semantiği kullanmaz sürümünden daha az kopya, bellek ayırma ve bellek ayırmayı kaldırma işlemlerini gerçekleştirdiğinden daha verimli sürümüdür.

Güçlü Programlama

Kaynak sızıntılarını önlemek için her zaman kaynakları (bellek, dosya tanıtıcıları ve yuvaları gibi) taşıma, atama işleci boş.

Kaynakların düzeltilemez imha önlemek için taşıma atama işleci, self-assignment doğru işlemeyebilir.

Sınıfınız için bir taşıma kurucusu hem de taşıma atama işleci sağlarsanız, taşıma atama işlecini çağırmak için taşıma kurucunuzu yazarak artıklı kod çıkarabilirsiniz. Aşağıdaki örnek, taşıma atama işleci çağrı taşıma yapıcı halini gösterir:

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

Std::move işlevi rvalue özelliğini korur other parametresi.

Ayrıca bkz.

Başvuru

Rvalue başvuru Bildiricisi: & &

Diğer Kaynaklar

<utility> move