大家都知道c/c++中對記憶體進行動態申請的時候, 堆上開闢的空間一定要進行釋放, 否則造成了記憶體洩漏是一件十分危險的事情, 但是我們在平時寫**的時候, 難免會忘記釋放空間, 或者當程式丟擲異常的時候, 釋放空間的**被跳過, 執行到, 這都是造成記憶體洩漏的原因. 為了解決這一情況, c++中引入了智慧型指標,來對動態開闢的記憶體進行管理.
raii的思想是指,利用物件的生命週期來對程式的資源進行管理, 即對乙個泛型的指標進行封裝, 以乙個物件的身份來管理動態開闢的空間, 而不單單是乙個指標的身份.
當我們要進行動態記憶體的開闢是, 可以建立乙個只能指標的物件, **在該物件的建構函式中進行空間的申請, 在物件的析構函式中進行空間的釋放.**這樣不僅解決了不需要使用者手動釋放空間的問題, 還保證了, 資源在物件的生命週期內始終有效.
接下來實現乙個簡單的實現raii思想的指標
template
<
class
t>
class
autoptr
~autoptr()
cout<<
"~autoptr()"
<
}private
: t* _ptr;};
void
fun(
)int
main()
catch
(const exception& e)
catch(.
..)return0;
}
上述程式中, 由於vector的開闢長度太長, 當層序執行到此處是,就會丟擲異常, 程式就會轉調到main程式中的捕獲異常出, 但是fun函式中的對p指標的釋放就沒有執行到, 這樣就造成了記憶體洩漏.
我們將fun函式改為如下程式
void
fun(
)
此時即使我們的fun函式中丟擲異常, 但是當程式跳轉到main函式中的時候, 也就是fun函式生命週期結束的時候, 會呼叫p物件的析構, 從而對空間進行釋放.
注意 : 只能指標在進行使用時, 必須保證開闢空間與常見物件在同一步進行,new操作符返回的是乙個指標型別, 因此直接在物件的構造中使用new操作符
當然, 只能指標的實現,還包括了指標的功能
template
<
class
t>
class
autoptr
~autoptr()
cout<<
"~autoptr()"
<
} t&
operator*(
) t*
operator
->()
private
: t* _ptr;
};
int
main()
注意 : 既然只能實現指標的基本操作,那麼就也有指標的拷貝與賦值操作, 指標的拷貝呼叫的是類的預設拷貝構造, 而預設拷貝構造只是乙個淺拷貝, 淺拷貝只拷貝值, 不會拷貝物件中的空間, 因此在執行上述**後,就會造成兩個指標指向同一塊空間, 這樣當main函式的生命週期執行完之後, 在對 p ,p1進行洗後的時候, 會對同一塊空間釋放兩次, 這樣回導致程式的崩潰
在stl中的auto_ptr是最早的一款智慧型指標, 它對指標的拷貝問題的解決是, 永遠保證只有乙個智慧型指標指向乙個空間, 當對當前智慧型指標進行拷貝的時候, 就將原來的指標置空.
在上述的 autoptr中對建構函式與賦值運算子過載進行修改
template
<
class
t>
class
autoptr
~autoptr()
cout<<
"~autoptr()"
<
}autoptr
(autoptr
& p)
autoptr
&operator
=(autoptr
& p)
_ptr=p._ptr;
p._ptr=
nullptr;}
} t&
operator*(
) t*
operator
->()
private
: t* _ptr;
};
注意 : 由於auto_ptr只能有乙個智慧型指標指向空間, 因此auto_ptr是乙個不完善的智慧型指標, 因此禁止使用
由於auto_ptr的不完備性, 容易造成空間的二次釋放, 因此c++11中有提供了乙個unique_ptr, 他處理問題的方法很簡單, 直接將拷貝構造與賦值運算子過載封死, 就最簡單的解決了問題.
template
<
class
t>
class
uniqueptr
~uniqueptr()
cout<<
"~autoptr()"
<
} t&
operator*(
) t*
operator
->()
uniqueptr
(autoptr&)
=delete
;operator
=(autoptr&)
=delete
;private
: t* _ptr;
};
在c++11中還有乙個更加全面的智慧型指標 sheard_ptr 它實現了前面倆個智慧型指標不能實現的拷貝與賦值.
它的原理是, 在智慧型指標的內部增加乙個計數器, 當有多個智慧型指標指向一塊空間是, 計數器就會加一, 當執行指正物件執行析構的時候, 先對計數器進行減一操作, 之後在判斷計數器的結果是否為零, 如果為零,則對空間進行釋放, 不為零則不作操作.
template
<
class
t>
class
sharedptr
~sharedptr()
}shareptr
(shareptr
& p)
;_ptr
(p._ptr)
,_count
(p._count)
shareptr
&operator
=(shareptr
& p)
_ptr=p._ptr;
_count=p._count;}(
*_count)++;
} t&
operator*(
) t*
operator
->()
intgitcount()
private
: t* _ptr;
int* _count;
};
注意:在shared_ptr的賦值運算子操作中, 賦值操作是將乙個指標替換成另乙個, 所以是要對指標記性判空, 刪除原來的值,在進行賦值, 而在shared_ptr中, 就需要先判斷_count的值是否是0 如果是0 則delete 之後賦值, 如果不是, 則直接改變智慧型指標內部的成員的值即 c 智慧型指標
auto prt 它是 它所指向物件的擁有者 所以當自身物件被摧毀時候,該物件也將遭受摧毀,要求乙個物件只有乙個擁有者,注意 auto prt 不能使用new 來分配物件給他 include include using namespace std template void bad print au...
c 智慧型指標
很久沒寫部落格了,不知道如何表達了,哈哈.我先介紹一下深淺拷貝.class copy 此時a.ptr和b.ptr指向同乙個物件,當我們delete a.ptr時 b.ptr所指向的物件已經不存在了,要是我們引用b.ptr指向的物件也就會出問題了.深拷貝 把a.ptr所指向的物件拷貝乙份給b.ptr ...
c 智慧型指標
記得前不久有一次面試被問到智慧型指標的實現,當時對智慧型指標只是聽說但沒有了解過,就亂七八糟地說了一遍。今天寫了一遍智慧型指標,用了引用計數的概念。主要思想就是,用乙個新類對原本需要的型別進行了一層封裝,這個新類中儲存了原本的物件指標和乙個引用計數的指標,之所以全部用指標來儲存,就是因為會出現多個新...