C/C++筆記 : Pass by Value 與 Pass by Reference 與 Pass by Address的差別

剛剛作為新鮮人在公司感覺有點被再教育了的感覺,一方面可能也是C#跟Java這種寫習慣了突然換回大一在用的C++結果被洗臉的感覺。再次感受到C#真的是很容易上手的語言,也重新回想起C++的pointer難關的感覺。

不過關關難過還是得要關關靠腰關關過(嘆),趕快趁著好人主管教完來做個筆記。

先來張可愛的ミク壓壓驚

喔,爽

------------------------------------------------

這邊自己覺得要先講一下C++變數的概念。

C++用了兩個容器來存所有的變數
如果你是用new出來的變數,他到死都不會被delete和釋放出記憶體空間。
這類變數會被放在Heap中

而其他非透過new的來宣告建立instance化的變數則是會被放在stack中,並有自己的生命周期(注意看一下{ }包到哪裡)


範例中的class結構 : 





Pass by Value


其實就是我們一般在C# / Java的那種寫法,沒有指標,沒有地址
使用這種傳法在C++的話會有一個情況需要去注意。

那就是,他並不是把你的參數傳進去,而是copy了一份你的參數內容然後在收到的那個function內產生一個一樣的變數去接你copy出來的結果,也就是說你在這邊修改變數的值,並不會直接連動影響到外部的值,兩邊變數的生命週期並不一樣,因為是兩個不一樣的變數。(C#就會連動了,這跟C#的特性有關,所以珍惜生命遠離C++)

然後我們在main裡寫這樣一段程式 : 


最後結果:

  • 在main裡面的Point pt此一物件,存在0042FC1C這個記憶體位置
  • 外面function中的p,他接了pt的資料,但是並不是pt本身,是新創的一個變數,存在0042FB44這個記憶體位置中
  • 外面function中的p,0042FB44這個記憶體位置裡面存了數值2
  • 但是在main裡面的Point pt,存在0042FC1C,因此外面function中的p (0042FB44)裡面的值變為2的時候,Point pt (0042FC1C)裡面的oint pt (0042FC1C)裡面的值並沒有跟著變,所以main裡面的pt並不會收到p的變化,因為已經是兩個分開出來的兩個變數了


Pass by Reference 




以往以為Pass by reference就是用pointer來傳值這樣。但其實不是。

Pass by reference真意是,我告訴你我的位置,那妳可以直接對我做操作
上面的這個function中,參數的部分就是PassByRef這個function會收到一個記憶體位置p,然後我知道他是Point型別的東西

也因此,操作的會是同一個變數,因為是對同一個記憶體區塊作操作。



可以發現:
  1. main內的Point point,他的記憶體位置是004FFA18
  2. function內收到的參數是直接拿到一個位置,這個參數Point p得到的位置是004FFA18
  3. 之後修改function內Point p (004FFA18)的數值為2
  4. 因為point跟p兩者的記憶體位置都是004FFA18,所以當前面在function中,p修改了004FFA18值的時候,pt的值也會收到變化變為2


Pass by Address (Pass by Pointer)


這邊有一個很重要的概念。

這其實根本就是Pointer版的Pass by value!

先撇去看到pointer就驚嚇萬分的狀況,回顧一下pointer的概念。
pointer也是一個變數,有自己的記憶體位置。他只是,存的東西是別人的位置而已。


所以我們一樣在main裡呼叫function
我們可以發現
p和point2這兩個pointer變數地址並不同,也就是說他跟pass by value一樣在function中重新宣告做了一個pointer變數p,然後去接point2變數的內容

所以可以發現
  1. 兩個pointer變數地址是不同的
  2. p的地點是00fafdb8
  3. point2的地址則是00fafeac
  4. 但是p的內容跟point2一樣,都是0145e618這個地址,是因為進到function的時候copy了一份point2的內容給了p
  5. PassByPointer()結束後,p就會因壽命到了從stack poppop出去
來看一下結果


為什麼值會一樣?

因為這TMD是Pointer。

Pass by Pointerointer這個function在收到以後產了生新的指標變數p去接Point類型的指標變數。
雖然兩個指標變數是不同的指標變數,但是兩個指標變數的內容是同樣的,也就是說他們指向著同一個記憶體區塊。

你用了「->」這個operate的話,就只是讓指標變數幫你「代行」呼叫使用那個記憶體中的Point 這個物件的Member function和 Data member。

也就是說

  • 我們用new創造了一個Point物件放在記憶體中,用一個Point型別的指標變數去指著記住這個空間。這個new出來的東西會一直存在記憶體中。
  • 然後我們把這個變數傳給function
  • function也自己建立了一個Point型別的指標變數p,然後copy你傳進來的指標變數point2的全部內容
  • function內由指標對記憶體中的Point物件做修改
  • function外的point2的內容 (記憶體中的Point物件位置),因為Point物件前面在function中被修改了所以function外的point2也會取道被修改的值。

剛剛主管還秀了一個Pass by reference的pointer版的操作

下次在寫這個好了,聽說很少用,這個就會跟前面 Point & p是一樣的概念了
他傳的是指標變數的位置,那妳可以直接去取用這個指標變數的意思。

大概是這樣吧。頭痛到不行。
誰發明C++的。



希望中國武漢肺炎早日結束讓我可以在出國參加演唱會

留言

這個網誌中的熱門文章

UE4 tutorial : Blueprints 筆記

UE4 tutorial : Materials 筆記

UE4 tutorial : Getting Started