亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C++ > 正文

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

2020-05-23 14:09:39
字體:
來源:轉載
供稿:網友
這篇文章主要介紹了C++中對構造函數和賦值運算符的復制和移動,是C++入門學習中的基礎知識,需要的朋友可以參考下
 

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

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

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

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

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

// spec1_copying_class_objects.cppclass Window{public: Window( const Window& ); // Declare copy constructor. // ...};int main(){}

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

移動構造函數和移動賦值運算符
下面的示例基于用于管理內存緩沖區的 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++ 類編寫移動構造函數和移動賦值運算符。
為 C++ 創建移動構造函數
定義一個空的構造函數方法,該方法采用一個對類類型的右值引用作為參數,如以下示例所示:

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

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

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

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

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

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

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

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

if (this != &other){}

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

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

執行第一個過程中的步驟 2 和步驟 3 以將數據成員從源對象轉移到要構造的對象:

// 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 類的完整移動構造函數和移動賦值運算符:

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

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

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

該示例產生下面的輸出:

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.

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

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


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产精品久久久久久久久久尿| 亚洲成人中文字幕| 欧美午夜精品久久久久久浪潮| 久99九色视频在线观看| 国产精品一区久久久| 国产欧美日韩精品在线观看| 黑人欧美xxxx| 日韩美女在线播放| 午夜精品理论片| 日韩国产精品亚洲а∨天堂免| 欧美日韩在线视频一区二区| 日韩美女在线播放| 亚洲欧美精品一区| 久久成人av网站| 91禁外国网站| 亚洲 日韩 国产第一| 在线观看欧美成人| 久久久精品中文字幕| 国产日韩在线播放| 亚洲欧美日韩成人| 亚洲iv一区二区三区| 91国在线精品国内播放| 精品亚洲夜色av98在线观看| 亚洲福利在线观看| 亚洲国模精品一区| 98精品国产高清在线xxxx天堂| 国产精品极品美女在线观看免费| 国内精品久久久久影院优| 国产一区二区在线免费| 久久久免费精品| 午夜精品在线观看| 中文字幕欧美日韩在线| 国产69精品久久久久9| 久久精品成人欧美大片古装| 欧美在线精品免播放器视频| 欧美日韩在线视频一区| 91国语精品自产拍在线观看性色| 日本久久久久亚洲中字幕| 国产精品永久免费视频| 亚洲香蕉成人av网站在线观看| 高清视频欧美一级| 国产精品免费久久久| 欧美黄网免费在线观看| 亚洲性生活视频在线观看| 久久成人免费视频| 欧美精品成人91久久久久久久| 国内免费精品永久在线视频| 亚洲精品资源在线| 日韩一区视频在线| 欧美孕妇孕交黑巨大网站| 国产精品99久久99久久久二8| 日韩在线一区二区三区免费视频| 久久好看免费视频| 97久久超碰福利国产精品…| 亚洲网站视频福利| 欧美国产日产韩国视频| 欧美极品欧美精品欧美视频| 国产欧美日韩中文| 一道本无吗dⅴd在线播放一区| 91免费看片网站| 91国产美女在线观看| 北条麻妃99精品青青久久| 88国产精品欧美一区二区三区| 亚洲国产精品va在线看黑人动漫| 精品国产一区二区三区四区在线观看| 欧美伦理91i| 97色伦亚洲国产| 在线成人激情黄色| 亚洲欧美成人一区二区在线电影| 国语自产精品视频在线看一大j8| 91理论片午午论夜理片久久| 欧美第一淫aaasss性| 国产在线日韩在线| 欧美激情乱人伦| 欧美精品xxx| 黑人精品xxx一区一二区| 色樱桃影院亚洲精品影院| 日韩有码片在线观看| 欧美精品免费看| 热re99久久精品国产66热| www.99久久热国产日韩欧美.com| 久久久久久久久国产| 欧美富婆性猛交| 国产一区二区黄| 亚洲精品电影在线| 91精品久久久久久综合乱菊| 亚洲精品国产精品乱码不99按摩| 久久久精品久久| 色哟哟亚洲精品一区二区| 精品国产一区二区三区久久狼5月| 国产精品美女免费看| 成人av资源在线播放| 成人伊人精品色xxxx视频| 精品久久香蕉国产线看观看gif| 国产小视频国产精品| 亚洲免费精彩视频| 久久久欧美一区二区| 羞羞色国产精品| 欧美成人一区二区三区电影| 亚洲第一偷拍网| 91精品久久久久久久| 国产一区二区在线播放| 国产日韩精品在线播放| 国产精品欧美激情在线播放| 欧美成人sm免费视频| 久久伊人精品一区二区三区| 国产日韩在线视频| 51ⅴ精品国产91久久久久久| 性色av一区二区三区在线观看| 欧美贵妇videos办公室| 中文在线不卡视频| 动漫精品一区二区| 国产一区二区色| 亚洲国产一区二区三区在线观看| 国产精品草莓在线免费观看| 国产日韩在线精品av| 亚洲精品国产综合区久久久久久久| 国产精品v日韩精品| 亚洲二区在线播放视频| 中文字幕日韩在线视频| 在线观看欧美日韩国产| 亚洲www在线| 亚洲黄色有码视频| 欧美视频不卡中文| 亚洲第一精品夜夜躁人人爽| 日韩电影网在线| 亚洲电影av在线| 亚洲一区二区三区在线免费观看| 欧美刺激性大交免费视频| 亚洲女人天堂网| 成人国产亚洲精品a区天堂华泰| 中文字幕亚洲综合久久| 97精品欧美一区二区三区| 国产自产女人91一区在线观看| 一区二区三区天堂av| 亚洲社区在线观看| 黑人极品videos精品欧美裸| 日本亚洲精品在线观看| 国产精品久久久久久影视| 欧美午夜丰满在线18影院| 九色精品免费永久在线| 久久黄色av网站| xvideos亚洲| 欧美性xxxxx极品| 亚洲欧洲日韩国产| 欧美成人一区二区三区电影| 神马国产精品影院av| 菠萝蜜影院一区二区免费| 精品视频www| 秋霞成人午夜鲁丝一区二区三区| 国产美女精彩久久| 亚洲999一在线观看www| 米奇精品一区二区三区在线观看| 国产亚洲精品91在线| 亚洲区一区二区| 亚洲欧洲在线播放| 日韩经典中文字幕| 日韩免费不卡av| 国产999精品| 57pao成人永久免费视频| 欧洲成人在线观看| 97视频免费观看| 亚洲中国色老太| 成人免费高清完整版在线观看|