新聞中心
在編程語(yǔ)言中,對(duì)堆對(duì)象的內(nèi)存管理是一個(gè)麻煩又復(fù)雜的問(wèn)題。一不小心就會(huì)帶來(lái)問(wèn)題,比如JS里一直引用一個(gè)已經(jīng)不使用的對(duì)象導(dǎo)致gc無(wú)法回收,或者C++里多個(gè)變量指向同一塊內(nèi)存導(dǎo)致重復(fù)釋放。本文簡(jiǎn)單探討一下關(guān)于對(duì)象所有權(quán)的問(wèn)題。

創(chuàng)新互聯(lián)長(zhǎng)期為1000+客戶(hù)提供的網(wǎng)站建設(shè)服務(wù),團(tuán)隊(duì)從業(yè)經(jīng)驗(yàn)10年,關(guān)注不同地域、不同群體,并針對(duì)不同對(duì)象提供差異化的產(chǎn)品和服務(wù);打造開(kāi)放共贏平臺(tái),與合作伙伴共同營(yíng)造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為隨州企業(yè)提供專(zhuān)業(yè)的網(wǎng)站制作、成都做網(wǎng)站,隨州網(wǎng)站改版等技術(shù)服務(wù)。擁有10多年豐富建站經(jīng)驗(yàn)和眾多成功案例,為您定制開(kāi)發(fā)。
對(duì)象的所有權(quán)意味著當(dāng)我們分配一個(gè)對(duì)象的時(shí)候,誰(shuí)持有這個(gè)對(duì)象的所有權(quán),比如下面代碼。
- Object *obj = new Object();
那么obj就持有了對(duì)象的所有權(quán)。但是現(xiàn)實(shí)往往比較復(fù)雜,比如我們看看下面代碼。
- #include
- using namespace std;
- class Demo {
- public:
- ~Demo(){
- printf("執(zhí)行析構(gòu)函數(shù)");
- }};void test() {
- Demo *d = new Demo();
- }
- int main(){
- test();
- return 0;
- }
執(zhí)行上面的代碼,我們?cè)趖est函數(shù)里分配一個(gè)堆對(duì)象,執(zhí)行完test后我們發(fā)現(xiàn)Demo對(duì)象的析構(gòu)函數(shù)并沒(méi)有執(zhí)行,這就造成了內(nèi)存泄漏。那我們需要怎么做呢?我們需要收到釋放對(duì)象對(duì)應(yīng)的內(nèi)存。修改一下test函數(shù)的代碼。
- void test() {
- Demo *d = new Demo();
- delete d;
- }
這時(shí)候我們發(fā)現(xiàn)就會(huì)輸出執(zhí)行析構(gòu)函數(shù)幾個(gè)字了,說(shuō)明析構(gòu)函數(shù)被執(zhí)行,對(duì)象的內(nèi)存也被釋放了。手動(dòng)管理內(nèi)存不僅麻煩,而且往往容易出錯(cuò),比如我們往往會(huì)忘了釋放,尤其是代碼邏輯復(fù)雜的時(shí)候。這時(shí)候,我們可以使用智能指針解決這個(gè)問(wèn)題。
- #include
- #include
- using namespace std;
- class Demo {
- public:
- ~Demo(){
- printf("執(zhí)行析構(gòu)函數(shù)");
- }
- };
- template
- class SmartPoint
- {
- T* point;
- public:
- SmartPoint(T *ptr = nullptr) :point(ptr) {}
- ~SmartPoint() {
- if (point) {
- // 會(huì)調(diào)用point指向?qū)ο蟮牡奈鰳?gòu)函數(shù)
- delete point;
- }
- }
- // 使用智能指針就像使用內(nèi)部包裹的的對(duì)象一樣
- T& operator*() {
- return *point;
- }
- T* operator->() {
- return point;
- }
- };
- void test() {
- SmartPoint
p(new Demo()); - }
- int main(){
- test();
- return 0;
- }
智能指針的原理比較簡(jiǎn)單,因?yàn)橹悄苤羔槍?duì)象是在棧上面分配的,離開(kāi)作用域的時(shí)候會(huì)被自動(dòng)釋放,然后在智能指針的析構(gòu)函數(shù)里釋放包裹的內(nèi)部對(duì)象。看起來(lái)是很完美的解決方案。但是智能指針也帶來(lái)了一些問(wèn)題,那就是在復(fù)制或賦值的時(shí)候。我們看看代碼。
- int main(){
- SmartPoint
p(new Demo()); - SmartPoint
p2 = p; - return 0;
- }
執(zhí)行下面代碼會(huì)導(dǎo)致core dump,為什么呢?我們來(lái)看看這個(gè)過(guò)程。當(dāng)執(zhí)行p2=p的時(shí)候會(huì)導(dǎo)致p2和p的內(nèi)部指針point都指向了Demo對(duì)象的地址,最后代碼執(zhí)行完畢后,兩個(gè)智能指針都執(zhí)行了釋放內(nèi)存的操作,重復(fù)釋放內(nèi)存導(dǎo)致了core dump。那如何解決這個(gè)問(wèn)題呢?一種方式是復(fù)制一份point指向的內(nèi)存,但是我們可能不知道這個(gè)內(nèi)存多大,無(wú)法復(fù)制,另一種方式就是所有權(quán)轉(zhuǎn)移。我們繼續(xù)看代碼。
- #include
- #include
- using namespace std;
- class Demo {
- public:
- ~Demo(){
- printf("執(zhí)行析構(gòu)函數(shù)");
- }
- };
- template
- class SmartPoint
- {
- T* point;
- public:
- SmartPoint(T *ptr = nullptr) :point(ptr) {}
- // 實(shí)現(xiàn)復(fù)制構(gòu)造函數(shù)
- SmartPoint(SmartPoint & p) {
- // 指向p.point對(duì)應(yīng)的內(nèi)存
- point = p.point;
- // p.point置null
- p.point = nullptr;
- }
- ~SmartPoint() {
- if (point) {
- // 會(huì)調(diào)用point指向?qū)ο蟮牡奈鰳?gòu)函數(shù)
- delete point;
- }
- }
- // 使用智能指針就像使用內(nèi)部包裹的的對(duì)象一樣
- T& operator*() {
- return *point;
- }
- T* operator->() {
- return point;
- }
- };
- int main(){
- SmartPoint
p(new Demo()); - SmartPoint
p2 = p; - return 0;
- }
我們實(shí)現(xiàn)了一個(gè)復(fù)制構(gòu)造函數(shù),在main里執(zhí)行p2=p時(shí)會(huì)被執(zhí)行,在復(fù)制構(gòu)造函數(shù)中,我們實(shí)現(xiàn)了所有權(quán)轉(zhuǎn)移,這時(shí)候p2時(shí)Demo對(duì)象的持有者,而p指向null,這時(shí)候不能再對(duì)p進(jìn)行操作。這時(shí)候我們可以在SmartPoint中實(shí)現(xiàn)一個(gè)isNull函數(shù)用于判斷智能指針的有效性。
- bool isNull() {
- return point == nullptr;
- }
然后在使用的地方加一下判斷。
- if (p.isNull()) {
- //
- }
這顯然很麻煩。我們看看Rust怎么做。
- struct Demo(u32);
- fn main() {
- let _box1 = Box::new(Demo(1));
- // 所有權(quán)轉(zhuǎn)移
- let _box2 = _box1;
- // 報(bào)錯(cuò)
- println!("{}", _box1.0);
- }
編譯上面代碼會(huì)報(bào)錯(cuò),是編譯而不是運(yùn)行,這就是Rust,在編譯期就解決了這個(gè)問(wèn)題。Box是智能指針,以上代碼和剛才C++中的代碼類(lèi)似,當(dāng)執(zhí)行_box2=_box1的時(shí)候,堆對(duì)象的所有權(quán)就轉(zhuǎn)移到了_box2,_box1相當(dāng)于包裹了一個(gè)空指針,而Rust不允許你再訪問(wèn)_box1管理里的內(nèi)存。
網(wǎng)頁(yè)名稱(chēng):聊聊智能指針和所有權(quán)的問(wèn)題
瀏覽路徑:http://fisionsoft.com.cn/article/cddpiic.html


咨詢(xún)
建站咨詢(xún)
