指針都離開作用域了,其所指向的對象如果只有指針一種方式才能訪問,那麼該對象不就沒辦法訪問了嗎,這不就內存泄漏了嗎?

C++ primer


因為沒人能確保只有這個指針在訪問。但是你可以改用unique_ptr來向C++編譯器表達這個事情,你的願望就實現了。

引用的話,如果觸發了「const T保留臨時對象」的這個機制的話,也可以析構。


你說的其實就是智能指針啊……

理想條件下所有訪問都通過智能指針來(意思就是不能指針不能引用,也不能取地址),不能共享的用unique,能共享的用shared,恭喜你,你的需求被實現了。

但是用裸指針是不行的。

C++是靠RAII保證在離開作用域時回收棧上元素。但是棧上的指針和對象之間的關係(所有權)是曖昧不清的。我覺得至少有三個解決辦法:

1.人為製造約定,也就是智能指針。

2.追溯關係來源,但不約束編碼行為。編譯器表示我好難,靜態分析好累,一個basic block還好,全程序真是做不動。

而且一旦涉及運行時行為,靜態分析就可能傻掉了。

3.追溯關係來源,並約束編碼行為。也就是編譯器分析不出來就報錯,於是成功把「如何讓程序不泄漏」轉化成了「如何讓程序編譯過」,可喜可賀。

shared_ptr的理念是用間接指針,在控制塊裏存運行期的引用信息,所以不用靜態分析但有運行時開銷。

tracing gc的理念稍微不同,不主動存被引用信息,但通過間接指針把引用信息分散在各個角落,於是需要主動發起gc來遍歷蒐集。


編譯器沒法以最大的善/惡意推斷你要幹嘛……

Something* func(){
Something a;
return a;
}

這種代碼它也會老老實實的傳一個指向棧上的野指針出來。

或者說,編譯器更相信你(作者)能夠管理好自己的資源,知道什麼時候該釋放資源。


指針離開作用域,指針變數本身的內存會釋放。

指針指向的內存沒有釋放,這是c++編譯器的選擇。

為什麼編譯器要這樣抉擇? 反例說明。

假設指針離開作用域,就會立馬析構並釋放指向的對象,會發生什麼事情?

當多個指針指向同一個對象,由於某個指針離開作用域就釋放了對象, 那麼沒有任何通知的情況下,指向這個對象的其他指針就都指向非法地址了,導致程序發生錯誤。

所以管理好內存,需要程序員手動new和delete對象。

但是就像你疑惑的, 指針退出作用域,對象卻不能自動釋放,很容易造成內存泄漏;複雜的程序中,也可能不小心就多次delete。

靠程序員修養是很不穩定的一件事情。

所以智能指針出現了,c++11起,有幾種不同的智能指紋分別用於不同的應用場景,自動管理所指向對象的生命週期。

c++程序員不用再小心翼翼的管理對象內存,頭髮又茂密了起來。


指針其實相當於銀行卡,存在銀行的錢相當於指針指向的內容。總不能我不小心把銀行卡搞丟了,錢就歸銀行了吧?


指針本身就是一個簡單的內置數據類型,與int, float, char並無兩樣,在內聲明,隨著棧的退出而銷毀,即使他指向一個對象(堆上內存空間), 如果不顯示的delete,他所指向的內存空間並不會被釋放。這應該就是c++不同於其他編程語言的地方,例如java。程序員自己需要有一個清晰的內存的概念,知道有多少個指針對一個對象進行管理,在什麼時候應該delete。

因為這個問題對程序員的要求很高,c++利用RAII(resource acquisitionn is initialization)機制,引入智能指針來管理/釋放對象(一般智能指針並不分配內存,通常是類模版的構造函數分配內存)。


恭喜你,你已經理解了unique_ptr是幹什麼的了。

順著這思路下去想想其他情況,比如好幾個指向一個,或者互相指向,你就能順便理解shared_ptr和weak_ptr了。

加油!


要明白一個道理,那就是析構函數,是在對象銷毀時執行,這裡是對象。一個指針或者應用,一般情況下,是在堆上分配的空間,拿到的指針或者引用,這是這個對象的地址。

可以嘗試下,你在棧空間生成一個對象,然後獲取他的地址,函數退出,棧清空以後,你這對象還在嗎?肯定不在了,這個時候就執行了析構函數。

所以我們的對區域進行區分。如果在棧空間,定義的一個變數對象,那麼你退出棧,你的對象就析構了。如果在堆空間,你定義了一個變數對象。用指針或者引用保存了對象地址。如果你沒有手動進行銷毀,那麼在程序結束前,地址一直有效。他是一直存在的。也就不會調用析構函數。

如果你想離開時析構,請看看智能指針吧。


推薦閱讀:
相關文章