溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C++中右值引用與移動語義的方法是什么

發(fā)布時間:2023-03-31 11:16:40 來源:億速云 閱讀:132 作者:iii 欄目:開發(fā)技術

今天小編給大家分享一下C++中右值引用與移動語義的方法是什么的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。

    意義

    充分利用臨時對象,避免拷貝。

    左值右值

    值類別

    在 C++11之后,C++根據(jù)

    • 被標識:可通過不同標識符指代同一實體。(對象/內存)

    • 可移動:可作為移動語義函數(shù)的參數(shù),例如移動構造,移動賦值。

    將值分為以下類別:

    泛左值:被標識

    • 左值:被標識且不可移動

    • 將亡值:被標識可移動

    右值:可移動

    • 將亡值:被標識可移動

    • 純右值:不被標識且可移動

    左值

    int a = 1;

    a是一個左值,左值是關聯(lián)了名稱的內存位置。

    純右值

    int a = 1;

    1是一個純右值,純右值是指不被標識且可移動的值,例如字面量。

    將亡值

    using std::string;
    string get()
    {
    	string ret = "abc";
    	return ret;
    }
    
    string str = get();

    get() 函數(shù)調用會產生一個臨時變量賦給str,這個臨時變量是將亡值,此時的賦值是移動語義(c++11之前是復制語義)。

    左值引用

    int a = 1;
    int& a_lref = a;

    a_lref是左值引用

    右值引用

    int&& rref = 1;

    rref是右值引用(rref是類型為右值引用的左值)

    std::move()

    void foo(int&& rref)
    {
    }
    
    int a = 1;
    foo(std::move(a));

    std::move本質是類型轉換,即把左值轉換成右值

    注意:被轉換的對象不應再被使用,否則結果難以預計(通常內存會被轉移)

    移動構造&移動賦值運算符重載

    class Foo
    {
    
    public:
    	Foo()
    	{
    		m_data = malloc(32);
    	}
    	
    	Foo(const Foo& rhs)
    	{
    		if(m_data == nullptr)
    		{
    			m_data = malloc(32);
    		}
    		memcopy(m_data,rhs.m_data,32);
    	}
    	
    	Foo& operator = (const Foo& rhs)
    	{
    		if(m_data == nullptr)
    		{
    			m_data = malloc(32);
    		}
    		memcopy(m_data,rhs.m_data,32);
    		return *this;
    	}
    	
    	Foo(Foo&& rhs) noexcept
    	{
    		m_data = rhs.m_data;
    		rhs.m_data = nullptr;
    	}
    	
    	Foo& operator = (Foo&& rhs) noexcept
    	{
    		m_data = rhs.m_data;
    		rhs.m_data = nullptr;
    		return *this;
    	}
    private:
    	void* m_data
    }

    移動構造的本質就是內存資源所有權的轉移

    測試&驗證

    #include <iostream>
    #include <cstdlib>
    
    #define LOG(Args) std::cout << "==== " << Args << " ====" << std::endl
    
    namespace My
    {
    	class Vector
    	{
    	public:
    		Vector() noexcept
    		{
    			LOG("Ctor");
    			m_data = new int[] {0, 0, 0, };
    		}
    
    		~Vector()
    		{
    			LOG("Dector");
    			m_data = new int[] {0, 0, 0, };
    		}
    
    		Vector(const Vector& rhs)
    		{
    			LOG("Copy");
    			if (m_data == nullptr)
    			{
    				m_data = new int[3];
    			}
    			memcpy(m_data, rhs.m_data, 3 * sizeof(int));
    
    		}
    
    		Vector& operator = (const Vector& rhs) 
    		{
    			LOG("Copy Operator = ");
    			if (m_data == nullptr)
    			{
    				m_data = new int[3];
    			}
    			memcpy(m_data, rhs.m_data, 3 * sizeof(int));
    			return *this;
    		};
    
    		Vector& operator = (Vector&& rhs) noexcept
    		{
    			LOG("Move Operator = ");
    			m_data = rhs.m_data;
    			rhs.m_data = nullptr;
    			return *this;
    		};
    
    		Vector(Vector&& rhs) noexcept
    		{
    			LOG("Move");
    			m_data = rhs.m_data;
    			rhs.m_data = nullptr;
    		}
    
    		void print()
    		{
    			std::cout << "X = " << m_data[0] <<
    				" , " << "Y = " << m_data[1] <<
    				" , " << "Z = " << m_data[2] << std::endl;
    		}
    
    		void set(int x,int y,int z)
    		{
    			m_data[0] = x;
    			m_data[1] = y;
    			m_data[2] = z;
    		}
    
    	private:
    		int* m_data;
    	};
    }
    
    My::Vector Get()
    {
    	My::Vector vec;
    	vec.set(4, 5, 6);
    	return vec;
    }
    
    void main()
    {
    	My::Vector vec1;
    	My::Vector vec2;
    
    	LOG("vec1");
    	vec1.print();
    
    	vec1.set(0, 1, 2);
    	LOG("vec1");
    	vec1.print();
    
    	vec1 = vec2;
    	LOG("vec1");
    	vec1.print();
    
    	vec1 = std::move(vec2);
    	LOG("vec1");
    	vec1.print();
    
    	My::Vector* vp1 = new My::Vector();
    	LOG("vp1");
    	vp1->print();
    
    	My::Vector* vp2 = new My::Vector(*vp1);
    	LOG("vp2");
    	vp2->print();
    
    	My::Vector* vp3 = new My::Vector(std::move(*vp1));
    	LOG("vp3");
    	vp3->print();
    
    	My::Vector* vp4 = new My::Vector(Get());
    	LOG("vp4");
    	vp4->print();
    }

    輸出

    C++中右值引用與移動語義的方法是什么

    以上就是“C++中右值引用與移動語義的方法是什么”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業(yè)資訊頻道。

    向AI問一下細節(jié)

    免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經查實,將立刻刪除涉嫌侵權內容。

    c++
    AI