欧美大屁股bbbbxxxx,狼人大香伊蕉国产www亚洲,男ji大巴进入女人的视频小说,男人把ji大巴放进女人免费视频,免费情侣作爱视频

歡迎來到入門教程網(wǎng)!

C語言

當(dāng)前位置:主頁 > 軟件編程 > C語言 >

詳解C++中對構(gòu)造函數(shù)和賦值運(yùn)算符的復(fù)制和移動(dòng)操作

來源:本站原創(chuàng)|時(shí)間:2020-01-10|欄目:C語言|點(diǎn)擊: 次

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

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

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

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

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

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

int main()
{
}

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

移動(dòng)構(gòu)造函數(shù)和移動(dòng)賦值運(yùn)算符
下面的示例基于用于管理內(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++ 類編寫移動(dòng)構(gòu)造函數(shù)和移動(dòng)賦值運(yùn)算符。
為 C++ 創(chuàng)建移動(dòng)構(gòu)造函數(shù)
定義一個(gè)空的構(gòu)造函數(shù)方法,該方法采用一個(gè)對類類型的右值引用作為參數(shù),如以下示例所示:

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

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

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

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

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

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

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

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

if (this != &other)
{
}

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

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

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

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

返回對當(dāng)前對象的引用,如以下示例所示:

return *this;

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

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

以下示例演示移動(dòng)語義如何能提高應(yīng)用程序的性能。此示例將兩個(gè)元素添加到一個(gè)矢量對象,然后在兩個(gè)現(xiàn)有元素之間插入一個(gè)新元素。在 Visual C++ 2010 中,vector 類使用移動(dòng)語義,通過移動(dòng)矢量元素(而非復(fù)制它們)來高效地執(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.

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

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

網(wǎng)頁制作CMS教程網(wǎng)絡(luò)編程軟件編程腳本語言數(shù)據(jù)庫服務(wù)器

如果侵犯了您的權(quán)利,請與我們聯(lián)系,我們將在24小時(shí)內(nèi)進(jìn)行處理、任何非本站因素導(dǎo)致的法律后果,本站均不負(fù)任何責(zé)任。

聯(lián)系QQ:835971066 | 郵箱:835971066#qq.com(#換成@)

Copyright © 2002-2020 腳本教程網(wǎng) 版權(quán)所有