欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解C++中對構造函數(shù)和賦值運算符的復制和移動操作

 更新時間:2016年01月21日 16:58:11   投稿:goldensun  
這篇文章主要介紹了C++中對構造函數(shù)和賦值運算符的復制和移動,是C++入門學習中的基礎知識,需要的朋友可以參考下

復制構造函數(shù)和復制賦值運算符
從 C++ 11 中開始,該語言支持兩種類型的分配:復制賦值和移動賦值。 在本文中,“賦值”意味著復制賦值,除非有其他顯式聲明。 賦值操作和初始化操作都會導致對象被復制。
賦值:在將一個對象的值賦給另一個對象時,第一個對象將復制到第二個對象中。 因此,

Point a, b;
...
a = b;

導致 b 的值被復制到 a 中。
初始化:在以下情況下將進行初始化:聲明新對象、參數(shù)通過值傳遞給函數(shù)或值通過值從函數(shù)返回。
您可以為類類型的對象定義“復制”的語義。 例如,考慮此代碼:

TextFile a, b;
a.Open( "FILE1.DAT" );
b.Open( "FILE2.DAT" );
b = a;

前面的代碼可能表示“將 FILE1.DAT 的內(nèi)容復制到 FILE2.DAT”,也可能表示“忽略 FILE2.DAT 并使 b 成為 FILE1.DAT 的另一個句柄”。 您必須將適當?shù)膹椭普Z義附加到每個類,如下所示。
通過將賦值運算符 operator= 與對類類型的引用一起用作返回類型和 const 引用所傳遞的參數(shù)(例如,ClassName& operator=(const ClassName& x);)。
通過通過復制構造函數(shù)。 有關復制構造函數(shù)的詳細信息,請參閱聲明構造函數(shù)的規(guī)則。
如果不聲明復制構造函數(shù),編譯器將為你生成 member-wise 復制構造函數(shù)。  如果不聲明復制賦值運算符,編譯器將為你生成 member-wise 復制賦值運算符。 聲明復制構造函數(shù)不會取消編譯器生成的復制賦值運算符,反之亦然。 如果實現(xiàn)上述其中一項,建議您還實現(xiàn)另一項以使代碼的含義變得明確。
逐個成員賦值和初始化 中更詳細地介紹了逐個成員賦值。
復制構造函數(shù)采用了 class-name& 類型的參數(shù),其中 class-name 是為其定義構造函數(shù)的類的名稱。 例如:

// spec1_copying_class_objects.cpp
class Window
{
public:
 Window( const Window& ); // Declare copy constructor.
 // ...
};

int main()
{
}

說明:
盡可能創(chuàng)建該類型的復制構造函數(shù)的參數(shù) const class-name&。 這可防止復制構造函數(shù)意外更改從中復制它的對象。 它還支持從 const 對象進行復制。
編譯器生成的構造函數(shù)
編譯器生成的復制構造函數(shù)(如用戶定義的復制構造函數(shù))具有單個參數(shù)類型“對 class-name 的引用”。 當所有基類和成員類都具有聲明為采用 const class-name& 類型的單個參數(shù)的復制構造函數(shù)時,將引發(fā)異常。 在這種情況下,編譯器生成的復制構造函數(shù)的參數(shù)也是 const。
當復制構造函數(shù)的參數(shù)類型不是 const 時,通過復制 const 對象進行初始化將產(chǎn)生錯誤。 反之則不然:如果參數(shù)是 const,您可以通過復制不是 const 的對象進行初始化。
編譯器生成的賦值運算符遵循關于 const 的相同模式。 除非所有基類和成員類中的賦值運算符都采用 const class-name& 類型的參數(shù),否則它們將采用 class-name& 類型的單個參數(shù)。 在這種情況下,類的生成的賦值運算符采用 const 參數(shù)。
說明:
當虛擬基類由復制構造函數(shù)(編譯器生成或用戶定義的)初始化時,將只初始化這些基類一次:在構造它們時。
含義類似于復制構造函數(shù)的含義。 當參數(shù)類型不是 const 時,從 const 對象賦值將產(chǎn)生錯誤。 反之則不然:如果將 const 值賦給不是 const 的值,則賦值能成功。

移動構造函數(shù)和移動賦值運算符
下面的示例基于用于管理內(nèi)存緩沖區(qū)的 C++ 類 MemoryBlock。

// 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 != nullptr)
  {
   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.
};

以下過程介紹如何為示例 C++ 類編寫移動構造函數(shù)和移動賦值運算符。
為 C++ 創(chuàng)建移動構造函數(shù)
定義一個空的構造函數(shù)方法,該方法采用一個對類類型的右值引用作為參數(shù),如以下示例所示:

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

在移動構造函數(shù)中,將源對象中的類數(shù)據(jù)成員添加到要構造的對象:

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

將源對象的數(shù)據(jù)成員分配給默認值。 這樣可以防止析構函數(shù)多次釋放資源(如內(nèi)存):

other._data = nullptr;
other._length = 0;

為 C++ 類創(chuàng)建移動賦值運算符
定義一個空的賦值運算符,該運算符采用一個對類類型的右值引用作為參數(shù)并返回一個對類類型的引用,如以下示例所示:

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

在移動賦值運算符中,如果嘗試將對象賦給自身,則添加不執(zhí)行運算的條件語句。

if (this != &other)
{
}

在條件語句中,從要將其賦值的對象中釋放所有資源(如內(nèi)存)。
以下示例從要將其賦值的對象中釋放 _data 成員:

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

執(zhí)行第一個過程中的步驟 2 和步驟 3 以將數(shù)據(jù)成員從源對象轉(zhuǎn)移到要構造的對象:

// 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 = nullptr;
other._length = 0;

返回對當前對象的引用,如以下示例所示:

return *this;

以下示例顯示了 MemoryBlock 類的完整移動構造函數(shù)和移動賦值運算符:

// Move constructor.
MemoryBlock(MemoryBlock&& other)
 : _data(nullptr)
 , _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 = nullptr;
 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 = nullptr;
  other._length = 0;
 }
 return *this;
}

以下示例演示移動語義如何能提高應用程序的性能。此示例將兩個元素添加到一個矢量對象,然后在兩個現(xiàn)有元素之間插入一個新元素。在 Visual C++ 2010 中,vector 類使用移動語義,通過移動矢量元素(而非復制它們)來高效地執(zhí)行插入操作。

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

該示例產(chǎn)生下面的輸出:

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.

使用移動語義的此示例版本比不使用移動語義的版本更高效,因為前者執(zhí)行的復制、內(nèi)存分配和內(nèi)存釋放操作更少。
可靠編程
若要防止資源泄漏,請始終釋放移動賦值運算符中的資源(如內(nèi)存、文件句柄和套接字)。
若要防止不可恢復的資源損壞,請正確處理移動賦值運算符中的自我賦值。
如果為您的類同時提供了移動構造函數(shù)和移動賦值運算符,則可以編寫移動構造函數(shù)來調(diào)用移動賦值運算符,從而消除冗余代碼。以下示例顯示了調(diào)用移動賦值運算符的移動構造函數(shù)的修改后的版本:

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

相關文章

  • C/C++語言宏定義使用實例詳解

    C/C++語言宏定義使用實例詳解

    這篇文章主要介紹了 C/C++語言宏定義使用實例詳解的相關資料,需要的朋友可以參考下
    2017-06-06
  • C++處理圖存儲的方式分享

    C++處理圖存儲的方式分享

    這篇文章主要介紹了C++處理圖存儲的方式分享,文章圍繞鄰接矩陣、鄰接表、鏈式前向的主題展開詳細內(nèi)容,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-03-03
  • Qt中QZXing 的編譯與使用

    Qt中QZXing 的編譯與使用

    本文主要介紹了Qt中QZXing 的編譯與使用,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • 關于C++繼承你可能會忽視的點

    關于C++繼承你可能會忽視的點

    繼承是面向?qū)ο笕筇匦灾?有些類與類之間存在特殊的關系,下面這篇文章主要給大家介紹了關于C++繼承你可能會忽視的點,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-02-02
  • C語言之結構體(struct)詳解

    C語言之結構體(struct)詳解

    本文主要介紹C語言 結構體的知識,學習C語言肯定需要學習結構體,這里詳細說明了結構體并附示例代碼,供大家參考學習,有需要的小伙伴可以參考下
    2021-10-10
  • C++學習筆記之pimpl用法詳解

    C++學習筆記之pimpl用法詳解

    在編寫穩(wěn)定代碼是,管理好代碼間的依賴性是不可缺少的一個環(huán)節(jié)。特別是庫文件的編寫中,減少代碼間的依賴性可以提供一個“干凈”的接口。下面這篇文章主要給大家介紹了關于C++中pimpl用法的相關資料,需要的朋友可以參考下。
    2017-08-08
  • C++處理鍵盤輸入的方法

    C++處理鍵盤輸入的方法

    這篇文章主要介紹了C++處理鍵盤輸入的方法,是C++程序設計中非常實用的技巧,需要的朋友可以參考下
    2014-10-10
  • 深入淺析C語言中堆棧和隊列

    深入淺析C語言中堆棧和隊列

    這篇文章主要介紹了深入淺析C語言中堆棧和隊列的相關資料,需要的朋友可以參考下
    2016-06-06
  • C++簡明分析inline函數(shù)的使用

    C++簡明分析inline函數(shù)的使用

    inline是C++關鍵字,在函數(shù)聲明或定義中,函數(shù)返回類型前加上關鍵字inline,即可以把函數(shù)指定為內(nèi)聯(lián)函數(shù)。這樣可以解決一些頻繁調(diào)用的函數(shù)大量消耗??臻g(棧內(nèi)存)的問題
    2022-07-07
  • vs2019安裝及簡單處理技巧(超詳細)

    vs2019安裝及簡單處理技巧(超詳細)

    這篇文章主要介紹了vs2019安裝及簡單處理方法,本文是一篇非常詳細的教程,通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-06-06

最新評論