[筆記]C++拷貝構造和移動構造


一、拷貝構造

  如果一個構造函數的第一個參數是自身類類型的引用,且任何額外參數都沒有默認值,則此構造函數是拷貝構造函數。(《C++Primer,第五版》)

class Foo
{
public :
    Foo();
    Foo(const Foo&); //拷貝構造函數
    Foo& operator=(const Foo&); //拷貝賦值運算符
};

  類的成員中有指針時,使用深拷貝。

#include <iostream>
using namespace std;

class Foo
{
public:
    Foo()
    {
        pInt = new int;
        *pInt = 1;
    }
    Foo(const Foo&)= default; //拷貝構造函數
    Foo& operator=(const Foo&) = default; //拷貝賦值運算符

    int* pInt;
};

//淺拷貝,foo1和foo2中的pInt指向同一塊內存地址
Foo foo1;
Foo foo2(foo1);

//深拷貝
class Cop
{
public:
    Cop()
    {
        pInt = new int;
        *pInt = 2;
    }
    Cop(const Cop& cop)
    {
        pInt = new int;
        *pInt = *(cop.pInt);
    }
    int* pInt;
};
//深拷貝,cop1和cop2中pInt指向不同內存
Cop cop1;
Cop cop2(cop1);

二、移動構造

  在某些情況下(函數返回對象引用),對象拷貝后立即就被消耗了。拷貝構造就回造成性能上的浪費,而且深拷貝也會造成浪費。移動構造可以避免這種情況的發生。

  為了支持移動構造,C++11引入了右值引用。

  右值引用:必須綁定到右值的引用,通過&&來獲得右值引用,類似左值引用(常規引用),右值應用也是一塊內存的別名。

  右值:字面常量、在表達式求值過程中臨時創建的對象,這些使用過后就被銷毀的資源。不同於左值的持久狀態。

  因此,右值引用只能綁定到將要被銷毀的對象上,左值引用只能綁定到持久的對象上。

//例子來源於  《C++primer 第五版》

int i = 42;
int& r = i;        //正確,i是左值
int&& rr = i;    //錯誤
int& r2 = i * 42;    //錯誤,i*42是右值,用完即銷毀
const int& r3 = i * 42;    //正確,隱式轉換為左值后,r3引用
int&& rr2 = i * 42;    //正確,綁定右值
int&& rr1 = 42;  //正確,字面常量是右值
int&& rr2 = rr1;  //錯誤,rr1左值

   變量都是左值,因此無法將右值引用綁定到一個右值引用類型的變量上。

   如果要將右值引用綁定到左值上,可以通過move函數來獲得左值的右值引用類型。對一個左值調用move函數后,除了對該左值賦值和銷毀外,不再使用它。

int i = 42;
int&& rr = move(i);

//i和rr引用同一塊內存

i = 32;

cout << i << endl;
cout << rr << endl;

   移動構造函數依靠右值引用特性來將來改變內存的管理者,而不同於拷貝構造對內存進行拷貝。

   移動構造:第一個參數是該類類型的一個右值引用,且任何額外的參數都必須有默認實參。使用移動構造函數必須確保銷毀移后源對象是無害的(不會重復釋放同一塊內存)。

Cop(Cop&& cop) noexcept : pInt(cop.pInt)
{
    cout << "this is &&" << endl;
    cop.pInt = NULL;
}
Cop& operator=(Cop&& cop) noexcept
{
   if ( this == &cop ) return *this; cout
<< "this is && =" << endl; delete pInt; pInt = cop.pInt; cop.pInt = NULL; } Cop retCop() { Cop cop3; *cop3.pInt = 3; return cop3; } //調用移動賦值運算符,cop3中pInt接管retCop返回對象中的pInt指向內存 Cop cop3 = retCop();

  noexcept承諾函數不拋出異常,標准庫對這個函數不做額外處理。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM