C++實例分析講解臨時對象與右值引用的用法

1.什麼是臨時變量

在棧上定義對象時,當隻調用類中的構造函數時,編譯器將在棧上創建一個臨時對象,這個臨時對象沒有地址。所以他的生命周期非常短。短到下一行代碼就被直接析構瞭。

代碼驗證

#include <iostream>
using namespace std;
class A
{
public:
    A()
    {
        cout<<"A的構造"<<endl;
    }
    virtual ~A()
    {
        cout<<"A的析構"<<endl;
    }
    A(const A& other)
    {
        cout<<"A的拷貝構造"<<endl;
    }
    virtual void show_info()
    {
        cout<<"我是父親"<<endl;
    }
};
class B:public A
{
public:
    B()
    {
        cout<<"B的構造"<<endl;
    }
    ~B()
    {
        cout<<"B的析構"<<endl;
    }
    void show_info()
    {
        cout<<"我是父親"<<endl;
    }
};
int main()
{
    A a=B();
    a.show_info();
    return 0;
}

結果圖:

如圖所示,現在我們來分析結果,首先這是一個拷貝構造,拷貝構造指的是用一個已經初始化的值,去初始化另一個沒有初始化的值,前兩行的構造都是臨時變量的構造,然後開始拷貝構造,拷貝構造完成之後,立馬對兩個臨時構造進行析構,這個就證明瞭當隻調用類中的構造函數時,編譯器將在棧上創建一個臨時對象,最後一個析構是拷貝構造的析構。

像這種情況我們就無法使用這個臨時變量,我們可以通過const常引用的方式來解決,我們都知道,我們無法直接int &a=100,無法直接引用一個常量,這個時候我們可以const int &a=100;所以,我們用這個方法來實現一下,代碼如下:

但是這個時候我們會發現,常引用隻能引用常函數,所以我們還必須把引用的函數加上const,但是這個在工作過程中,基本上是不現實,也是不方便的。

#include <iostream>
using namespace std;
class A
{
public:
    A()
    {
        cout<<"A的構造"<<endl;
    }
    virtual ~A()
    {
        cout<<"A的析構"<<endl;
    }
    A(const A& other)
    {
        cout<<"A的拷貝構造"<<endl;
    }
    virtual void show_info()const
    {
        cout<<"我是父親"<<endl;
    }
};
class B:public A
{
public:
    B()
    {
        cout<<"B的構造"<<endl;
    }
    ~B()
    {
        cout<<"B的析構"<<endl;
    }
    void show_info()const
    {
        cout<<"我是父親"<<endl;
    }
};
int main()
{
    const A& a=B();
    a.show_info();
    return 0;
}

結果圖:

雖然我們得到瞭這樣一個結果圖,但是這是不方便得,所以我們就引出來瞭右值引用。

註意:此時B()已經不是一個臨時變量瞭,他有瞭地址,所以,現在這個就相當於

    //相當於const A& a=B();
    int temp=&B的地址,把B的地址進行保存。註意這個是在棧上。
    //可能有些人會這麼理解
    B* b=new B;
    A&& a=std::move(*(b));
    a.show_info();
    //但是我們註意瞭右值引用不能用在堆上,並且這種寫法肯定也是不對的

成為瞭多態的一個條件瞭。

2.右值引用

2.1概念

左值:有地址的量就是左值。

右值:沒有地址量就是右值。

右值引用的語法形式:

右值引用類型&& 引用變量 = 常量或臨時對象

2.2代碼實現

#include <iostream>
using namespace std;
class A
{
public:
    A()
    {
        cout<<"A的構造"<<endl;
    }
    virtual ~A()
    {
        cout<<"A的析構"<<endl;
    }
    A(const A& other)
    {
        cout<<"A的拷貝構造"<<endl;
    }
    virtual void show_info()
    {
        cout<<"我是父親"<<endl;
    }
};
class B:public A
{
public:
    B()
    {
        cout<<"B的構造"<<endl;
    }
    ~B()
    {
        cout<<"B的析構"<<endl;
    }
    void show_info()
    {
        cout<<"我是父親"<<endl;
    }
};
int main()
{
    A&& a=B();
    a.show_info();
//也可以使用,
    A&& a1=std::move(a);
    a.show_info();
    return 0;
}

結果圖:

用瞭右值引用我們就可以不用在加const瞭,也是我們工作開發中常用的。

註意:我在這個代碼裡面寫瞭兩個可以調用多態的方法,第二個方法,如果一個右值想引用一個左值時,必須使用std::mover函數,此時如果不加A&&,相當於一個拷貝構造。

2.3C++11新特性之移動構造

2.3.1移動構造函數的介紹

1.首先我們討論一下移動構造函數的優缺點,有瞭移動構造我們就不用再開辟新的空間,提高瞭效率,但是也有它的缺點,缺點就是這玩意不是很安全,我們可以在這個裡面修改這個值,可能會導致一些問題。

2.就是我們可能會想為什麼我們不能把這個移動構造的邏輯直接,加入到拷貝構造中呢,隻需要把const直接去掉不就一樣的瞭麻,但是如果我們把const去掉之後,我們other就不能是個常數瞭,這樣就導致瞭缺點,所以,移動構造函數是拷貝函數的一個優化補充。

2.3.2代碼實現

#include <iostream>
using namespace std;
class A
{
    int *a;
public:
    A():a(new int[1024])
    {
        cout<<"A的構造"<<endl;
    }
    A(const A& other)
    {
        a=new int[1024];
        memcpy(this->a,other.a,sizeof (int[1024]));
    }
    A(A&& other)
    {
        this->a=other.a;
        other.a=nullptr;
        cout<<"A的移動構造"<<endl;
    }
    ~A()
    {
        if(a!=nullptr){
            delete [] a;
            cout<<"A的析構"<<endl;
        }
    }
};
int main()
{
    A a;
    A a1=std::move(a);
    return 0;
}

結果圖:

這樣就隻析構瞭一次就是正確的瞭。

到此這篇關於C++實例分析講解臨時對象與右值引用的用法的文章就介紹到這瞭,更多相關C++臨時對象與右值引用內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: