最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++從匯編的視角審視對(duì)象的創(chuàng)建問(wèn)題

 更新時(shí)間:2022年01月21日 09:20:06   作者:楷哥  
這篇文章主要介紹了C++從匯編的視角看對(duì)象的創(chuàng)建,從匯編的視角來(lái)看,調(diào)用構(gòu)造器和調(diào)用 “返回對(duì)象” 的函數(shù)是一樣的,從匯編的角度來(lái)看,對(duì)象就是一堆數(shù)據(jù)的排列,比如說(shuō)最普通的對(duì)象就是數(shù)據(jù)成員按照聲明順序直接排列,需要的朋友可以參考下

前言

很久以前閱讀了 CSAPP 這本書(shū),可惜看過(guò)的東西基本都忘記了,只知道一些工具可以幫助我分析。今天突然對(duì) “返回對(duì)象的函數(shù)” 很感興趣,于是分析了一下匯編。

返回對(duì)象的函數(shù)如下,現(xiàn)在有一種叫做 NRV 優(yōu)化的技術(shù)可以避免低效率,如果把它關(guān)掉,它將會(huì)執(zhí)行以下過(guò)程:創(chuàng)建一個(gè)對(duì)象 apple,然后返回一個(gè) apple,發(fā)生一次拷貝構(gòu)造函數(shù),所以存在執(zhí)行效率問(wèn)題;如果你還寫(xiě)了 Apple a = GetApple();,那么還將會(huì)發(fā)生一次賦值拷貝構(gòu)造。

Apple GetApple() {
	Apple apple{};
	return apple;
}

代碼:

class Apple {
public:
	Apple() {
	}
	~Apple() {
	}
	Apple(const Apple& apple) {
		this->a = apple.a;
		this->b = apple.b;
	}
	Apple& operator=(const Apple& apple) {
		this->a = apple.a;
		this->b = apple.b;
		return *this;
	}
  void Print() {
    cout << a << " " << b << endl;
  }

	int a = 1;
	int b = 2;
};

Apple GetApple() {
	Apple apple{};
	return apple;
}

構(gòu)造函數(shù)的執(zhí)行過(guò)程分析

構(gòu)造函數(shù)的執(zhí)行過(guò)程:即使是無(wú)參構(gòu)造函數(shù),調(diào)用之前仍然要傳參。傳入的是一個(gè)地址,需要在函數(shù)運(yùn)行結(jié)束的時(shí)候,這個(gè)地址上有了一個(gè)對(duì)象。

main 函數(shù)如下:

int main() {
  Apple a;
  int x = a.a;
  x = 10;
  return 0;
}

生成的匯編代碼:

# main 函數(shù)構(gòu)造對(duì)象的地方:
	pushq	%rbp              # rbp 壓棧
	movq	%rsp, %rbp        # rsp 替換 rbp
	pushq	%rbx              # rbx 壓棧,保存現(xiàn)場(chǎng)
	subq	$24, %rsp         # rsp 自減 24,棧向下增長(zhǎng),相當(dāng)于擴(kuò)展 24 字節(jié)
	leaq	-24(%rbp), %rax   # 將地址賦值給 rax,rax 是 Apple 對(duì)象開(kāi)始的地方
	movq	%rax, %rdi        # rdi 傳參
	call	_ZN5AppleC1Ev
	movl	-28(%rbp), %eax   # 返回之后,會(huì)執(zhí)行 int x = a.a;
	movl	%eax, -20(%rbp)   # 取第一個(gè)字節(jié)賦值給 x
	movl	$10, -20(%rbp)    # 直接使用 10 賦值給 x;寫(xiě)著行的目的只是為了確定 x 的位置

# 默認(rèn)構(gòu)造器:
	pushq	%rbp              # rbp 壓棧
	movq	%rsp, %rbp        # rsp 替換 rbp
	movq	%rdi, -8(%rbp)    # rdi 是前面 rax 的值
	movq	-8(%rbp), %rax    # 設(shè)置 rax 為 rbp 減 8
	movl	$1, (%rax)        # 間接尋址,設(shè)置 4 字節(jié)為 1
	movq	-8(%rbp), %rax    # rax 其實(shí)還是一樣的
	movl	$2, 4(%rax)       # 變址尋址,其實(shí)就是間接尋址加一個(gè)偏移量,設(shè)置 4 字節(jié)為 2
	nop
	popq	%rbp
	ret                       # 于是最終 rdi 開(kāi)始,向下的 8 字節(jié)是 Apple 對(duì)象

返回對(duì)象函數(shù)的分析

從匯編的視角來(lái)看,調(diào)用構(gòu)造器和調(diào)用 “返回對(duì)象” 的函數(shù)是一樣的。它的執(zhí)行過(guò)程是:即使是兩個(gè)函數(shù)都是無(wú)參的,它仍然會(huì)進(jìn)行一次傳參。傳入的是一個(gè)地址,需要在函數(shù)調(diào)用結(jié)束后,這個(gè)地址上有了一個(gè)對(duì)象。從匯編的角度來(lái)看,對(duì)象就是一堆數(shù)據(jù)的排列,比如說(shuō)最普通的對(duì)象就是數(shù)據(jù)成員按照聲明順序直接排列。

舉個(gè)實(shí)際點(diǎn)的例子。Apple 這個(gè)類,有兩個(gè)成員,a 和 b。調(diào)用了構(gòu)造器或者 “返回對(duì)象” 的函數(shù),先傳入一個(gè)地址,之后函數(shù)里面會(huì)在這個(gè)地址上存放兩個(gè)數(shù),分別是 a 和 b 的值,然后返回。此時(shí),這個(gè)地址上就有了 a 和 b,雖然機(jī)器看不到對(duì)象,但是對(duì)我們來(lái)說(shuō),它就是一個(gè)對(duì)象。

如果關(guān)閉了 NRV 優(yōu)化,那么首先會(huì)傳入一個(gè)地址,然后構(gòu)造一個(gè)對(duì)象,這個(gè)對(duì)象將會(huì)被拷貝構(gòu)造到傳入的地址上,返回。之后如果調(diào)用了一次賦值,那么還要將這個(gè)地址上的對(duì)象復(fù)制構(gòu)造給棧上的變量。整個(gè)過(guò)程,實(shí)際上存在兩個(gè)臨時(shí)對(duì)象,發(fā)生了一次構(gòu)造、一次復(fù)制構(gòu)造、一次賦值構(gòu)造。

main:
.LFB3535:
	pushq	%rbp
	movq	%rsp, %rbp
	pushq	%rbx
	subq	$40, %rsp
	leaq	-36(%rbp), %rax
	movq	%rax, %rdi
	call	_ZN5AppleC1Ev
	movl	-36(%rbp), %eax
	movl	%eax, -20(%rbp)
	movl	$10, -20(%rbp)
	leaq	-28(%rbp), %rax    # 這里之前的匯編是一樣的,調(diào)用 GetApple
	movq	%rax, %rdi         # rdi,傳參
	call	_Z8GetApplev        
	leaq	-28(%rbp), %rdx    # rax 已經(jīng)存放對(duì)象,-28 的位置有對(duì)象
	leaq	-36(%rbp), %rax
	movq	%rdx, %rsi
	movq	%rax, %rdi
	call	_ZN5AppleaSERKS_
	leaq	-28(%rbp), %rax
	movq	%rax, %rdi
	call	_ZN5AppleD1Ev
	movl	$0, %ebx
	leaq	-36(%rbp), %rax
	movq	%rax, %rdi
	call	_ZN5AppleD1Ev
	movl	%ebx, %eax
	addq	$40, %rsp
	popq	%rbx
	popq	%rbp

# GetApple 函數(shù)的匯編代碼
	pushq	%rbp
	movq	%rsp, %rbp
	subq	$32, %rsp
	movq	%rdi, -24(%rbp)    # 分配空間,然后將傳過(guò)來(lái)的 rdi 放進(jìn)去
	leaq	-8(%rbp), %rax     
	movq	%rax, %rdi         # 前面分析過(guò)了,調(diào)用回來(lái)時(shí) rax 開(kāi)始的 8 字節(jié)就是對(duì)象
	call	_ZN5AppleC1Ev
	leaq	-8(%rbp), %rdx     # 取 rax 地址到 rdx
	movq	-24(%rbp), %rax    # 取 rdi 地址到 rax
	movq	%rdx, %rsi         # rsi 已經(jīng)有對(duì)象了
	movq	%rax, %rdi         # rsi 和 rdi 都用來(lái)傳參          
	call	_ZN5AppleC1ERKS_   # 調(diào)用拷貝構(gòu)造函數(shù)
	leaq	-8(%rbp), %rax     # rax 上有對(duì)象了
	movq	%rax, %rdi         # rdi 傳參,準(zhǔn)備調(diào)用析構(gòu)函數(shù)
	call	_ZN5AppleD1Ev
	nop
	movq	-24(%rbp), %rax    # 前面調(diào)用拷貝構(gòu)造前的地址,這個(gè)地址有對(duì)象了
	leave
	ret

# 拷貝構(gòu)造函數(shù)
	pushq	%rbp
	movq	%rsp, %rbp
	movq	%rdi, -8(%rbp)    # rdi 無(wú)對(duì)象
	movq	%rsi, -16(%rbp)   # rsi 有對(duì)象
	movq	-16(%rbp), %rax   # 把對(duì)象放到 rax
	movl	(%rax), %edx      # 把第一屬性(4 字節(jié))移動(dòng)到 edx
	movq	-8(%rbp), %rax
	movl	%edx, (%rax)      # 把第一屬性移動(dòng)到 rdi
	movq	-16(%rbp), %rax
	movl	4(%rax), %edx     # 把第二屬性移動(dòng)到 edx
	movq	-8(%rbp), %rax
	movl	%edx, 4(%rax)     # 把第二屬性移動(dòng)到 rdi 上
	movq	-8(%rbp), %rax    # rdi 上有了對(duì)象,rax 也設(shè)置一個(gè)
	popq	%rbp
	ret

到此這篇關(guān)于C++:從匯編的視角看對(duì)象的創(chuàng)建的文章就介紹到這了,更多相關(guān)C++匯編對(duì)象內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Qt TCP實(shí)現(xiàn)簡(jiǎn)單通信功能

    Qt TCP實(shí)現(xiàn)簡(jiǎn)單通信功能

    這篇文章主要為大家詳細(xì)介紹了Qt TCP實(shí)現(xiàn)簡(jiǎn)單通信功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • VC運(yùn)用OPENGL加載BMP紋理圖的實(shí)現(xiàn)方法匯總

    VC運(yùn)用OPENGL加載BMP紋理圖的實(shí)現(xiàn)方法匯總

    這篇文章主要介紹了VC運(yùn)用OPENGL加載BMP紋理圖的實(shí)現(xiàn)方法,對(duì)于更好的了解OpenGL很有幫助,需要的朋友可以參考下
    2014-07-07
  • C語(yǔ)言?typedef的用法示例詳解

    C語(yǔ)言?typedef的用法示例詳解

    typedef是在C和C++編程語(yǔ)言中的一個(gè)關(guān)鍵字,作用是為現(xiàn)有的數(shù)據(jù)類型(int、float、char……)創(chuàng)建一個(gè)新的名字,目的是為了使代碼方便閱讀和理解,這篇文章主要介紹了C語(yǔ)言typedef的使用,需要的朋友可以參考下
    2023-06-06
  • C++ Opengl旋轉(zhuǎn)功能附源碼下載

    C++ Opengl旋轉(zhuǎn)功能附源碼下載

    這篇文章主要介紹了C++ Opengl旋轉(zhuǎn)功能附源碼下載,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-11-11
  • C語(yǔ)言文件操作總結(jié)

    C語(yǔ)言文件操作總結(jié)

    本篇文章給大家通過(guò)代碼示例講述了C語(yǔ)言文件操作的相關(guān)知識(shí)點(diǎn),對(duì)此有興趣的朋友可以參考學(xué)習(xí)下。
    2018-03-03
  • C語(yǔ)言16進(jìn)制與ASCII字符相互轉(zhuǎn)換

    C語(yǔ)言16進(jìn)制與ASCII字符相互轉(zhuǎn)換

    大家好,本篇文章主要講的是C語(yǔ)言16進(jìn)制與ASCII字符相互轉(zhuǎn)換,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下
    2022-01-01
  • C語(yǔ)言實(shí)現(xiàn)輸出1000以內(nèi)的所有完全數(shù)

    C語(yǔ)言實(shí)現(xiàn)輸出1000以內(nèi)的所有完全數(shù)

    這篇文章主要介紹了C語(yǔ)言實(shí)現(xiàn)輸出1000以內(nèi)的所有完全數(shù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-06-06
  • Opencv實(shí)現(xiàn)聯(lián)合雙邊濾波

    Opencv實(shí)現(xiàn)聯(lián)合雙邊濾波

    這篇文章主要為大家詳細(xì)介紹了Opencv實(shí)現(xiàn)聯(lián)合雙邊濾波,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • C++ LeetCode1781題解所有子字符串美麗值之和

    C++ LeetCode1781題解所有子字符串美麗值之和

    這篇文章主要為大家介紹了C++ LeetCode1781題解所有子字符串美麗值之和,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • Qt QCompleter自動(dòng)補(bǔ)全的實(shí)現(xiàn)

    Qt QCompleter自動(dòng)補(bǔ)全的實(shí)現(xiàn)

    本文主要介紹了Qt QCompleter自動(dòng)補(bǔ)全的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-04-04

最新評(píng)論

黎川县| 江山市| 苍溪县| 哈密市| 东丽区| 河北省| 翼城县| 武城县| 新营市| 大邑县| 卓资县| 沅陵县| 灵武市| 伊吾县| 河北区| 临沧市| 榆树市| 区。| 平顶山市| 南木林县| 民丰县| 三亚市| 泰州市| 鲜城| 盈江县| 永平县| 时尚| 湄潭县| 杭锦后旗| 洛阳市| 镇宁| 鸡东县| 大方县| 阳春市| 甘洛县| 湟中县| 连云港市| 高雄市| 兴和县| 平山县| 荆门市|