c 記憶體管理 指標的用法

2021-10-12 13:56:03 字數 3464 閱讀 7945

指標是記憶體能管理的重要組成部分。

new和delete運算子提供了一種比自動變數和靜態變數更靈活的方法。它們管理了乙個記憶體池,這在c++中被稱為自由儲存空間(free store)或堆(heap)。

該記憶體池同用於靜態變數和自動變數的記憶體是分開的。new和delete讓您能夠在乙個函式中分配記憶體,而在另乙個函式中釋放它。因此,資料的生命週期不完全受程式或函式的生存時間控制。與使用常規變數相比,使用new和delete讓程式設計師對程式如何使用記憶體有更大的控制權。然而,記憶體管理也更複雜了。在棧中,自動新增和刪除機制使得占用的記憶體總是連續的,但new和delete的

相互影響可能導致占用的自由儲存區不連續,這使得跟蹤新分配記憶體的位置更困難.

對空指標應用delete是安全的。

現在我們回過頭來討論動態陣列。psome是指向乙個int(陣列第乙個元素)的指標。您的責任是跟蹤記憶體塊中的元素個數。也就是說,由於編譯器不能對psome是指向10個整數中的第1個這種情況進行跟蹤,因此編寫程式時,必須讓程式跟蹤元素的數目。

實際上,程式確實跟蹤了分配的記憶體量,以便以後使用delete 運算子時能夠正確地釋放這些記憶體。但這種資訊不是公用的,例如,不能使用sizeof運算子來確定動態分配的陣列包含的位元組數。

智慧型指標是為了防止忘記釋放指標指向內容,或者因為程式異常而釋放指標**不可達導致的記憶體洩漏而發明的一種模板類.

用法極其類似於原生指標卻可以自動釋放指向內容,本質是乙個模板.

原理是對普通型別的指標進行一次封裝,並對其進行作用域檢測,一旦超出作用域,而內部封裝的指標的引用減1.

也就是說, 智慧型指標, 用棧上的仿指標來管理堆上的指標, 用自動記憶體來管理手動記憶體.

智慧型指標為了呼叫析構函式,必須注意,操作的必須是使用new返回的指標。

有乙個問題是, 智慧型指標如何跨方法傳遞呢?

智慧型指標中,公有三種, auto_ptr, unique_ptr, shared_ptr.

為什麼 auto_ptr不如unique_ptr呢?

因為 auto_ptr 允許賦值運算,舉個例子, p2 = p1, 指標p1指向的物件會被轉移給另外乙個指標p2, 這樣做的目的是可以防止多次釋放同一塊記憶體. 也就是說, auto_ptr 賦值自帶物件轉移(或者拷貝建構函式).這即是其優點, 也是其缺點. 當p1再次被使用的時候(這是誤操作,但是卻難以避免), 卻有可能發現這個指標已經被釋放了(懸掛指標),從而引起程式崩潰, 這是執行時錯誤. 我們把p1 叫做懸掛指標.

而unique_ptr是不存在這種錯誤的.因為 unique_ptr 禁止了賦值運算子, 而這會被編譯器提前檢查出來, 所以提前暴露了錯誤, 屬於編譯錯誤. 但是, unique_ptr 可以接受臨時右值物件(按值返回的時候)的賦值, 這樣就不存在懸掛指標了.

如果非要對 unique_ptr 用賦值運算子, 使用move, 把左值變成右值. 但是這又會繼續產生懸掛指標的問題!

//

// created by zxzx on 2020/10/17.

//#include

#include

#include

using

namespace std;

template

<

typename t>

class

smartprt

;smartprt

(const smartprt& sp)

smartprt&

operator

=(smartprt& p)

t*operator

->()

; t&

operator*(

)~smartprt()

intgetrefcount()

private

: t* m_p;

int* m_refcount;

// 這個指標

void

decr()

}};class

test

;test

(string& i)

test

(string i)

test

(char

* i)

~test()

void

showname()

string&

getname()

private

: string name;};

void

test_ptr()

#endif

//zzz_smartptr_h

在上面講到, unique_ptr 是 auto_ptr 的改進, 那麼什麼時候用 unique_ptr 呢?

c++ primer plus上說, 只要不涉及多個指標指向同乙個物件的時候,可以使用 unique_ptr. 比如new來的物件.

但是這種情況一般比較少見吧.

反而, 在stl容器中, 經常出現多個指標指向同乙個元素, 因為要在元素上排序查詢等操作時, 使用多個指標是很常見的事.

右值到底是什麼?

從字面上理解, 右值就是放在 等號右邊,只能被賦值給變數, 而自己不能被賦值的"東西"的統稱.

比如乙個直接量, 乙個數字, 乙個字串, 乙個沒有名字的自定義型別臨時物件,甚至說, 乙個const型別的變數, 那都是右值.

右值的意義, 在於什麼地方? 右值的意義, 在於(1)提公升傳參效率(2)為了程式設計方便.

先說個簡單的, 為了程式設計方便. 右值是不能被輕易引用的. 乙個直接量之不能被傳入乙個要求按引用傳參的函式.

這樣就很麻煩, 要先宣告乙個常量引用, 然後再把這個引用傳進去.

呼叫函式傳參的時候, 有兩種方式, 乙個是按引用, 乙個是按值.

按值傳參, 就會呼叫拷貝建構函式.

如果乙個自定義類體積很大, 或者成員很多, 呼叫拷貝建構函式, 成本就很高.

如果這個物件的目的就是單純為了傳參, 而不需要保留原來的值, 那麼成本就確實顯得很高, 呼叫建構函式毫無必要.

為了能顧把右值當做形式引數使用, 定義了 t&& 的形式作為右值. 也就有了相應的右值建構函式,或者叫轉移建構函式,

它的目的就是滿足乙個變數僅僅作為傳參使用, 而不必另做備份之用.

右值有的時候可以變成左值, 比如當乙個形參是右值,然後被傳入另乙個函式內, 在這個函式裡, 它就是左值.

使用move 可以把乙個左值變成乙個右值. move()函式.

有乙個疑問就是, 既然憑藉引用可以傳參, 為什麼還有右值傳參呢? 說到底, 還是為了方便直接量, 或者臨時物件.

舉個例子

int main()
使用乙個直接量的時候, 系統會預設先使用移動建構函式, 如果沒有的話,就是呼叫拷貝建構函式.(成本相對高).

編譯器是可以自動識別左值和右值的.

最後補充乙個內容. 為什麼移動建構函式要用swap 而不是 檢查是否是同乙個物件呢?

因為每次檢查是否是自身, 有成本, 而且真正發生頻率也不高, 而且swap可以復用**, 並且延遲釋放原來指標. 總之, 好處大於壞處.

指標(記憶體管理)

直接上總結 四種指標 前倆種是泛型 後倆種是普通的指標 unsafepointer unsafemutablepointer unsaferawpointer unsafemutablerawpointer 簡單示例 一 1.泛型指標示例 2.普通指標示例 3.應用示例 獲得變數的指標 二 1.示例...

再談c的記憶體管理及指標問題

記憶體空間主要由五個部分組成 段 text 資料段 data bss段 bss 堆和棧組成,其中 段,資料段和bss段是編譯的時候由編譯器分配的,而堆和 棧是程式執行的時候由系統分配的。布局如下 下面分別解釋各段 bss段 用來存放程式中未初始化的全域性變數和靜態變數 初始化分為顯式和隱式初始化,未...

c 智慧型指標與記憶體管理

c 中當我們需要新分配記憶體的時候需要手動的去呼叫new顯式的分配一塊記憶體,如果我們在任何中new 如函式中申請空間返回 忘記釋放,或者在 函式執行過程中出現異常,沒 有執行釋放語句 了空間,在不需要使用後忘記了呼叫delete這塊位址的話就會造成 記憶體洩露。為了解決這乙個問題引入了智慧型指標。...