国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【重學(xué)C++】04 | 說(shuō)透C++右值引用、移動(dòng)語(yǔ)義、完美轉(zhuǎn)發(fā)(上)

這篇具有很好參考價(jià)值的文章主要介紹了【重學(xué)C++】04 | 說(shuō)透C++右值引用、移動(dòng)語(yǔ)義、完美轉(zhuǎn)發(fā)(上)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

文章首發(fā)

【重學(xué)C++】04 | 說(shuō)透C++右值引用、移動(dòng)語(yǔ)義、完美轉(zhuǎn)發(fā)(上)

引言

大家好,我是只講技術(shù)干貨的會(huì)玩code,今天是【重學(xué)C++】的第四講,在前面《03 | 手?jǐn)]C++智能指針實(shí)戰(zhàn)教程》中,我們或多或少接觸了右值引用和移動(dòng)的一些用法。

右值引用是 C++11 標(biāo)準(zhǔn)中一個(gè)很重要的特性。第一次接觸時(shí),可能會(huì)很亂,不清楚它們的目的是什么或者它們解決了什么問(wèn)題。接下來(lái)兩節(jié)課,我們?cè)敿?xì)講講右值引用及其相關(guān)應(yīng)用。內(nèi)容很干,注意收藏!

左值 vs 右值

簡(jiǎn)單來(lái)說(shuō),左值是指可以使用&符號(hào)獲取到內(nèi)存地址的表達(dá)式,一般出現(xiàn)在賦值語(yǔ)句的左邊,比如變量、數(shù)組元素和指針等。

int i = 42;
i = 43; // ok, i是一個(gè)左值
int* p = &i; // ok, i是一個(gè)左值,可以通過(guò)&符號(hào)獲取內(nèi)存地址

int& lfoo() { // 返回了一個(gè)引用,所以lfoo()返回值是一個(gè)左值
	int a = 1;
	return a; 
};
lfoo() = 42; // ok, lfoo() 是一個(gè)左值
int* p1 = &lfoo(); // ok, lfoo()是一個(gè)左值

相反,右值是指無(wú)法獲取到內(nèi)存地址的表達(dá)是,一般出現(xiàn)在賦值語(yǔ)句的右邊。常見(jiàn)的有字面值常量、表達(dá)式結(jié)果、臨時(shí)對(duì)象等。

int rfoo() { // 返回了一個(gè)int類型的臨時(shí)對(duì)象,所以rfoo()返回值是一個(gè)右值
	return 5;
};

int j = 0;
j = 42; // ok, 42是一個(gè)右值
j = rfoo(); // ok, rfoo()是右值
int* p2 = &rfoo(); // error, rfoo()是右值,無(wú)法獲取內(nèi)存地址

左值引用 vs 右值引用

C++中的引用是一種別名,可以通過(guò)一個(gè)變量名訪問(wèn)另一個(gè)變量的值。

上圖中,變量a和變量b指向同一塊內(nèi)存地址,也可以說(shuō)變量a是變量b的別名。

在C++中,引用分為左值引用和右值引用兩種類型。左值引用是指對(duì)左值進(jìn)行引用的引用類型,通常使用&符號(hào)定義;右值引用是指對(duì)右值進(jìn)行引用的引用類型,通常使用&&符號(hào)定義。

class X {...};
// 接收一個(gè)左值引用
void foo(X& x);
// 接收一個(gè)右值引用
void foo(X&& x);

X x;
foo(x); // 傳入?yún)?shù)為左值,調(diào)用foo(X&);

X bar();
foo(bar()); // 傳入?yún)?shù)為右值,調(diào)用foo(X&&);

所以,通過(guò)重載左值引用和右值引用兩種函數(shù)版本,滿足在傳入左值和右值時(shí)觸發(fā)不同的函數(shù)分支。

值得注意的是,void foo(const X& x);同時(shí)接受左值和右值傳參。

void foo(const X& x);
X x;
foo(x); // ok, foo(const X& x)能夠接收左值傳參

X bar();
foo(bar()); // ok, foo(const X& x)能夠接收右值傳參

// 新增右值引用版本
void foo(X&& x);
foo(bar()); // ok, 精準(zhǔn)匹配調(diào)用foo(X&& x)

到此,我們先簡(jiǎn)單對(duì)右值和右值引用做個(gè)小結(jié):

  1. 像字面值常量、表達(dá)式結(jié)果、臨時(shí)對(duì)象等這類無(wú)法通過(guò)&符號(hào)獲取變量?jī)?nèi)存地址的,稱為右值。
  2. 右值引用是一種引用類型,表示對(duì)右值進(jìn)行引用,通常使用&&符號(hào)定義。

右值引用主要解決一下兩個(gè)問(wèn)題:

  1. 實(shí)現(xiàn)移動(dòng)語(yǔ)義
  2. 實(shí)現(xiàn)完美轉(zhuǎn)發(fā)

這一節(jié)我們先詳細(xì)講講右值是如何實(shí)現(xiàn)移動(dòng)效果的,以及相關(guān)的注意事項(xiàng)。完美轉(zhuǎn)發(fā)篇幅有點(diǎn)多,我們留到下節(jié)講。

復(fù)制 vs 移動(dòng)

假設(shè)有一個(gè)自定義類X,該類包含一個(gè)指針成員變量,該指針指向另一個(gè)自定義類對(duì)象。假設(shè)O占用了很大內(nèi)存,創(chuàng)建/復(fù)制O對(duì)象需要較大成本。

class O {
public:
	O() {
		std::cout << "call o constructor" << std::endl;
	};
	O(const O& rhs) {
		std::cout << "call o copy constructor." << std::endl;
	}
};

class X {
public:
	O* o_p;
	X() {
		o_p = new O();
	}
	~X() {
		delete o_p;
	}
};

X 對(duì)應(yīng)的拷貝賦值函數(shù)如下:

X& X::operator=(X const & rhs) {
	// 根據(jù)rhs.o_p生成的一個(gè)新的O對(duì)象資源
	O* tmp_p = new O(*rhs.o_p);
	// 回收x當(dāng)前的o_p;
	delete this->o_p;
	// 將tmp_p 賦值給 this.o_p;
	this->o_p = tmp_p;
	return *this;
}

假設(shè)對(duì)X有以下使用場(chǎng)景:

X x1;
X x2;
x1 = x2;

上述代碼輸出:

call o constructor
call o constructor
call o copy constructor

x1x2初始化時(shí),都會(huì)執(zhí)行new O(), 所以會(huì)調(diào)用兩次O的構(gòu)造函數(shù);執(zhí)行x1=x2時(shí),會(huì)調(diào)用一次O的拷貝構(gòu)造函數(shù),根據(jù)x2.o_p復(fù)制一個(gè)新的O對(duì)象。

由于x2在后續(xù)代碼中可能還會(huì)被使用,所以為了避免影響x2,在賦值時(shí)調(diào)用O的拷貝構(gòu)造函數(shù)復(fù)制一個(gè)新的O對(duì)象給x1在這種場(chǎng)景下是沒(méi)問(wèn)題的。

但在某些場(chǎng)景下,這種拷貝顯得比較多余:

X foo() {
	return X();
};

X x1;
x1 = foo();

代碼輸出與之前一樣:

call o constructor
call o constructor
call o copy constructor

在這個(gè)場(chǎng)景下,foo()創(chuàng)建的那個(gè)臨時(shí)X對(duì)象在后續(xù)代碼是不會(huì)被用到的。所以我們不需要擔(dān)心賦值函數(shù)中會(huì)不會(huì)影響到那個(gè)臨時(shí)X對(duì)象,沒(méi)必要去復(fù)制一個(gè)新的O對(duì)象給x1。

更高效的做法,是直接使用swap交換臨時(shí)X對(duì)象的o_px1.o_p。這樣做有兩個(gè)好處:1. 不用調(diào)用耗時(shí)的O拷貝構(gòu)造函數(shù),提高效率;2. 交換后,臨時(shí)X對(duì)象擁有之前x1.o_p指向的資源,在析構(gòu)時(shí)能自動(dòng)回收,避免內(nèi)存泄漏。

這種避免高昂的復(fù)制成本,而直接將資源從一個(gè)對(duì)象"移動(dòng)"到另外一個(gè)對(duì)象的行為,就是C++的移動(dòng)語(yǔ)義。

哪些場(chǎng)景適用移動(dòng)操作呢?無(wú)法獲取內(nèi)存地址的右值就很合適,我們不需要擔(dān)心后續(xù)的代碼會(huì)用到該右值。

最后,我們看下移動(dòng)版本的賦值函數(shù)

X& operator=(X&& rhs) noexcept {
	std::swap(this->o_p, rhs.o_p);
	return *this;
};

看下使用效果:

X x1;
x1 = foo();

輸出結(jié)果:

call o constructor
call o constructor

右值引用一定是右值嗎?

假設(shè)我們有以下代碼:

class X {
public:
	// 復(fù)制版本的賦值函數(shù)
	X& operator=(const X& rhs);

	// 移動(dòng)版本的賦值函數(shù)
	X& operator=(X&& rhs) noexcept;
};

void foo(X&& x) {
	X x1;
	x1 = x;
}

X重載了復(fù)制版本和移動(dòng)版本的賦值函數(shù)。現(xiàn)在問(wèn)題是:x1=x這個(gè)賦值操作調(diào)用的是X& operator=(const X& rhs)還是 X& operator=(X&& rhs)?
針對(duì)這種情況,C++給出了相關(guān)的標(biāo)準(zhǔn):

Things that are declared as rvalue reference can be lvalues or rvalues. The distinguishing criterion is:?if it has a name, then it is an lvalue. Otherwise, it is an rvalue.

也就是說(shuō),只要一個(gè)右值引用有名稱,那對(duì)應(yīng)的變量就是一個(gè)左值,否則,就是右值。

回到上面的例子,函數(shù)foo的入?yún)㈦m然是右值引用,但有變量名x,所以x是一個(gè)左值,所以operator=(const X& rhs)最終會(huì)被調(diào)用。

再給一個(gè)沒(méi)有名字的右值引用的例子

X bar();
// 調(diào)用X& operator=(X&& rhs),因?yàn)閎ar()返回的X對(duì)象沒(méi)有關(guān)聯(lián)到一個(gè)變量名上
X x = bar();

這么設(shè)計(jì)的原因也挺好理解。再改下foo函數(shù)的邏輯:

void foo(X&& x) {
	X x1;
	x1 = x;
	...
	std::cout << *(x.inner_ptr) << std::endl;
}

我們并不能保證在foo函數(shù)的后續(xù)邏輯中不會(huì)訪問(wèn)到x的資源。所以這種情況下如果調(diào)用的是移動(dòng)版本的賦值函數(shù),x的內(nèi)部資源在完成賦值后就亂了,無(wú)法保證后續(xù)的正常訪問(wèn)。

std::move

反過(guò)來(lái)想,如果我們明確知道在x1=x后,不會(huì)再訪問(wèn)到x,那有沒(méi)有辦法強(qiáng)制走移動(dòng)賦值函數(shù)呢?

C++提供了std::move函數(shù),這個(gè)函數(shù)做的工作很簡(jiǎn)單: 通過(guò)隱藏掉入?yún)⒌拿?,返回?duì)應(yīng)的右值。

X bar();
X x1
// ok. std::move(x1)返回右值,調(diào)用移動(dòng)賦值函數(shù)
X x2 = std::move(x1);
// ok. std::move(bar())與 bar()效果相同,返回右值,調(diào)用移動(dòng)賦值函數(shù)
X x3 = std::move(bar());

最后,用一個(gè)容易犯錯(cuò)的例子結(jié)束這一環(huán)節(jié)

class Base {
public:
	// 拷貝構(gòu)造函數(shù)
	Base(const Base& rhs);
	// 移動(dòng)構(gòu)造函數(shù)
	Base(Base&& rhs) noexcept;
};

class Derived : Base {
public:
	Derived(Derived&& rhs)
	// wrong. rhs是左值,會(huì)調(diào)用到 Base(const Base& rhs).
	// 需要修改為Base(std::move(rhs))
	: Base(rhs) noexcept {
		...
	}
}

返回值優(yōu)化

依照慣例,還是先給出類X的定義

class X {
public:
	// 構(gòu)造函數(shù)
	X() {
		std::cout << "call x constructor" <<std::endl;
	};
	// 拷貝構(gòu)造函數(shù)
	X(const X& rhs) {
		std::cout << "call x copy constructor" << std::endl;
	};
	// 移動(dòng)構(gòu)造函數(shù)
	X(X&& rhs) noexcept {
		std::cout << "call x move constructor" << std::endl
	};
}

大家先思考下以下兩個(gè)函數(shù)哪個(gè)性能比較高?

X foo() {
  X x;
  return x;
};

X bar() {
  X x;
  return std::move(x);
}

很多讀者可能會(huì)覺(jué)得foo需要一次復(fù)制行為:從x復(fù)制到返回值;bar由于使用了std::move,滿足移動(dòng)條件,所以觸發(fā)的是移動(dòng)構(gòu)造函數(shù):從x移動(dòng)到返回值。復(fù)制成本 > 移動(dòng)成本,所以bar性能更好。

實(shí)際效果與上面的推論相反,bar中使用std::move反倒多余了?,F(xiàn)代C++編譯器會(huì)有返回值優(yōu)化。換句話說(shuō),編譯器將直接在foo返回值的位置構(gòu)造x對(duì)象,而不是在本地構(gòu)造x然后將其復(fù)制出去。很明顯,這比在本地構(gòu)造后移動(dòng)效率更快。

以下是foobar的輸出:

// foo
call x constructor

// bar
call x constructor
call x move constructor

移動(dòng)需要保證異常安全

細(xì)心的讀者可能已經(jīng)發(fā)現(xiàn)了,在前面的幾個(gè)小節(jié)中,移動(dòng)構(gòu)造/賦值函數(shù)我都在函數(shù)簽名中加了關(guān)鍵字noexcept,這是向調(diào)用者表明,我們的移動(dòng)函數(shù)不會(huì)拋出異常。

這點(diǎn)對(duì)于移動(dòng)函數(shù)很重要,因?yàn)橐苿?dòng)操作會(huì)對(duì)右值造成破壞。如果移動(dòng)函數(shù)中發(fā)生了異常,可能會(huì)對(duì)程序造成不可逆的錯(cuò)誤。以下面為例

class X {
public:
	int* int_p;
	O* o_p;

	X(X&& rhs) {
		std::swap(int_p, rhs.int_p);
		...
		其他業(yè)務(wù)操作
		...
		std::swap(o_p, rhs.o_p);
	}
}

如果在「其他業(yè)務(wù)操作」中發(fā)生了異常,不僅會(huì)影響到本次構(gòu)造,rhs內(nèi)部也已經(jīng)被破壞了,后續(xù)無(wú)法重試構(gòu)造。所以,除非明確標(biāo)識(shí)noexcept,C++在很多場(chǎng)景下會(huì)慎用移動(dòng)構(gòu)造。

比較經(jīng)典的場(chǎng)景是std::vector 擴(kuò)縮容。當(dāng)vector由于push_backinsert、reserve、resize 等函數(shù)導(dǎo)致內(nèi)存重分配時(shí),如果元素提供了一個(gè)noexcept的移動(dòng)構(gòu)造函數(shù),vector會(huì)調(diào)用該移動(dòng)構(gòu)造函數(shù)將元素移動(dòng)到新的內(nèi)存區(qū)域;否則,則會(huì)調(diào)用拷貝構(gòu)造函數(shù),將元素復(fù)制過(guò)去。

總結(jié)

今天我們主要學(xué)了C++中右值引用的相關(guān)概念和應(yīng)用場(chǎng)景,并花了很大篇幅講解移動(dòng)語(yǔ)義及其相關(guān)實(shí)現(xiàn)。

右值引用主要解決實(shí)現(xiàn)移動(dòng)語(yǔ)義和完美轉(zhuǎn)發(fā)的問(wèn)題。我們下節(jié)接著講解右值是如何實(shí)現(xiàn)完美轉(zhuǎn)發(fā)。歡迎關(guān)注,及時(shí)收到推送~文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-455815.html

到了這里,關(guān)于【重學(xué)C++】04 | 說(shuō)透C++右值引用、移動(dòng)語(yǔ)義、完美轉(zhuǎn)發(fā)(上)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 【C++干貨鋪】C++11新特性——右值引用、移動(dòng)構(gòu)造、完美轉(zhuǎn)發(fā)

    【C++干貨鋪】C++11新特性——右值引用、移動(dòng)構(gòu)造、完美轉(zhuǎn)發(fā)

    ========================================================================= 個(gè)人主頁(yè)點(diǎn)擊直達(dá):小白不是程序媛 C++系列專欄:C++干貨鋪 代碼倉(cāng)庫(kù):Gitee ========================================================================= 目錄 左值與左值引用 右值與右值引用 左值引用和右值引用的比較 ?左值引用總結(jié):

    2024年01月25日
    瀏覽(19)
  • 【C++11】 initializer_list | 右值引用 | 移動(dòng)構(gòu)造 | 完美轉(zhuǎn)發(fā)

    【C++11】 initializer_list | 右值引用 | 移動(dòng)構(gòu)造 | 完美轉(zhuǎn)發(fā)

    { } 初始化 C++11 擴(kuò)大了括號(hào)括起的列表(初始化列表)的使用范圍,使其可用于所有的內(nèi)置類型和用戶自定義類型, 使用初始化列表,可添加等號(hào)(=),也可不添加 將1賦值給x1,x2處省略了賦值符號(hào),將5賦值給x2 同樣也可以將new開(kāi)辟4個(gè)int的空間初始化為0 創(chuàng)建對(duì)象時(shí),可以使用列

    2024年02月08日
    瀏覽(23)
  • c++積累8-右值引用、移動(dòng)語(yǔ)義

    c++積累8-右值引用、移動(dòng)語(yǔ)義

    1.1 背景 c++98中的引用很常見(jiàn),就是給變量取個(gè)別名,具體可以參考c++積累7 在c++11中,增加了右值引用的概念,所以c++98中的引用都稱為左值引用 1.2 定義 右值引用就是給右值取個(gè)名字,右值有了名字之后就成了普通變量,可以像使用左值一樣使用。 語(yǔ)法:數(shù)據(jù)類型 變量名

    2023年04月23日
    瀏覽(17)
  • 【C++學(xué)習(xí)】C++11——新特性 | 右值引用 | 完美轉(zhuǎn)發(fā)

    【C++學(xué)習(xí)】C++11——新特性 | 右值引用 | 完美轉(zhuǎn)發(fā)

    ??作者:一只大喵咪1201 ??專欄:《C++學(xué)習(xí)》 ??格言: 你只管努力,剩下的交給時(shí)間! C++的發(fā)展截至到目前為止,雖然版本有很多,但是C++11則帶來(lái)了數(shù)量可觀的變化,其中包含了約140個(gè)新特性,以及對(duì)C++03標(biāo)準(zhǔn)中約600個(gè)缺陷的修正,這使得C++11更像是從C++98/03中孕育出的一

    2024年02月06日
    瀏覽(20)
  • 【C++】—— C++11新特性之 “右值引用和移動(dòng)語(yǔ)義”

    【C++】—— C++11新特性之 “右值引用和移動(dòng)語(yǔ)義”

    前言: 本期,我們將要的介紹有關(guān) C++右值引用 的相關(guān)知識(shí)。對(duì)于本期知識(shí)內(nèi)容,大家是必須要能夠掌握的,在面試中是屬于重點(diǎn)考察對(duì)象。 目錄 (一)左值引用和右值引用 1、什么是左值?什么是左值引用? 2、什么是右值?什么是右值引用? (二)左值引用與右值引用比

    2024年02月11日
    瀏覽(21)
  • 從C語(yǔ)言到C++_33(C++11_上)initializer_list+右值引用+完美轉(zhuǎn)發(fā)+移動(dòng)構(gòu)造/賦值

    從C語(yǔ)言到C++_33(C++11_上)initializer_list+右值引用+完美轉(zhuǎn)發(fā)+移動(dòng)構(gòu)造/賦值

    目錄 1.?列表初始化initializer_list 2. 前面提到的一些知識(shí)點(diǎn) 2.1 小語(yǔ)法 2.2 STL中的一些變化 3. 右值和右值引用 3.1?右值和右值引用概念 3.2?右值引用類型的左值屬性 3.3?左值引用與右值引用比較 3.4?右值引用的使用場(chǎng)景 3.4.1 左值引用的功能和短板 3.4.2?移動(dòng)構(gòu)造 3.4.3?移動(dòng)賦值

    2024年02月12日
    瀏覽(36)
  • 【C++】 C++11(右值引用,移動(dòng)語(yǔ)義,bind,包裝器,lambda,線程庫(kù))

    【C++】 C++11(右值引用,移動(dòng)語(yǔ)義,bind,包裝器,lambda,線程庫(kù))

    C++11是C++語(yǔ)言的一次重大更新版本,于2011年發(fā)布,它包含了一些非常有用的新特性,為開(kāi)發(fā)人員提供了更好的編程工具和更好的編程體驗(yàn),使得編寫(xiě)高效、可維護(hù)、安全的代碼更加容易。 一些C++11的新增特性包括: 強(qiáng)制類型枚舉,使得枚舉類型的通常行為更加可靠和容易控制

    2024年02月10日
    瀏覽(20)
  • C++11『右值引用 ‖ 完美轉(zhuǎn)發(fā) ‖ 新增類功能 ‖ 可變參數(shù)模板』

    C++11『右值引用 ‖ 完美轉(zhuǎn)發(fā) ‖ 新增類功能 ‖ 可變參數(shù)模板』

    ?個(gè)人主頁(yè): 北 海 ??所屬專欄: C++修行之路 ??操作環(huán)境: Visual Studio 2022 版本 17.6.5 自從C++98以來(lái),C++11無(wú)疑是一個(gè)相當(dāng)成功的版本更新。它引入了許多重要的語(yǔ)言特性和標(biāo)準(zhǔn)庫(kù)增強(qiáng),為C++編程帶來(lái)了重大的改進(jìn)和便利。C++11的發(fā)布標(biāo)志著C++語(yǔ)言的現(xiàn)代化和進(jìn)步,為程序員

    2024年02月05日
    瀏覽(25)
  • C++左值右值完美轉(zhuǎn)發(fā)轉(zhuǎn)移

    英文含義: 左值(Lvalue) : Locator value ,意味著它指向一個(gè)具體的內(nèi)存位置。 右值(Rvalue) : Read value ,指的是可以讀取的數(shù)據(jù),但不一定指向一個(gè)固定的內(nèi)存位置。 定義 左值 :指的是一個(gè)持久的內(nèi)存地址。左值可以出現(xiàn)在賦值操作的左側(cè)或右側(cè)。例如,變量、數(shù)組的元

    2024年03月10日
    瀏覽(35)
  • C++ Primer閱讀筆記--對(duì)象移動(dòng)(右值引用、移動(dòng)迭代器和引用限定符的使用)

    目錄 1--右值引用 2--std::move 3--移動(dòng)構(gòu)造函數(shù) 4--移動(dòng)賦值運(yùn)算符 5--移動(dòng)迭代器 6--引用限定符 ? ? ? ? 右值引用必須綁定到右值的引用,通過(guò) 獲得右值引用; ????????右值引用只能綁定到 臨時(shí)對(duì)象 (即將被銷毀的對(duì)象),即所引用的對(duì)象將要被銷毀,對(duì)象沒(méi)有其他用戶;

    2024年02月10日
    瀏覽(39)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包