淺談auto_ptr
淺談auto_ptr
在寫C++的時候,常常會使用new來獲取heap的空間,來取得heap的空間,如下。
void Test1(){char* name = new char(100);//process something delete name; } char* GetHeap(char* name){char* name = new char(100);return name; }
然而對程式設計師來說,最麻煩的過於一旦new出空間後,一定要執行delete把空間回收,以免發生memory leak的行為
memory leak: 某塊記憶體再也沒有檔案去reference,當妳new出空間後,沒有去delete回收空間時,很容易發生
void Test2(){ char* name = new char(100); //要空間 }//沒有回收,就會造成剛剛取得的空間會變成記憶體中的孤兒
所以在學習 new/delete時,總是被不斷的叮嚀,有new就要有delete,一定要成對出現。
在C++的標準中,提供了一個叫做auto_ptr的標準,就是專門用來處理這種情況,
只要當這個指標沒有繼續reference時,便會自動回收自己,讓程式設計師更方便,能夠遠離new/delete之苦。
可惜如此良好想法的設計,在目前C++標準中,卻是不建議被使用的,因為其某些特性,反而會使得程式碼變得難以捉模。
以下就來正式介紹 auto_ptr
俗稱智慧型指標,保證只要本身被摧毀,必定釋放其所指資源
是一種指向所屬物件擁有者的指標。所以當身為物件擁有者的auto_ptr被摧毀時,該物件也會被摧毀
auto_ptr要求,一個物件只能有一個擁有者,嚴禁一物二主(這點卻造成困擾)
本身不支援指標算數(++之類)
不允許一般指標慣用的賦值初始化方式,必須直接使用顯示轉換來初始化,因為在其實作中,有使用到explicit關鍵字。
void Test3(){auto_ptr<int> ptr(new int[100]); //ok auto_ptr<int> ptr = new int[100]; //error //process something }
擁有權的轉移
auto_ptr 所界定的是嚴格的擁有權概念,由於一個auto_ptr會刪除所擁有的物件,不應該發生同時間有多個auto_ptr共同擁有一個物件
否則就會出現問題,程式設計師要特別小心避免寫出這樣的程式碼,
auto_ptr<int> ptr1(new int[100]); //declare a auto_ptr pointer toint *ptr1=123; //change value cout<<*ptr1<<endl;auto_ptr<int> ptr2(ptr1); //initial ptr2 via ptr1 and ptr1 trans its ownership if(ptr1.get()==NULL)cout<<"ptr1 has transfered ownership to ptr2"<<endl;cout<<*ptr2<<endl;return 0;------------------ output: 123 ptr1 has transfered ownership to ptr2 123
執行第二行的時候,ptr1會把所有權轉移給ptr2,所以此行一旦結束,ptr1就會是個null。
同樣的問題也會發生在assign的情況下
auto_ptr<int> ptr1(new int[100]); auto_ptr<int> ptr2; ptr2 = ptr1 ; //transfers ownership from ptr1 to ptr2
此外,如果ptr2被賦值前擁有另外一個物件,則被賦值後,便會釋放該物件,並呼叫destructor。
#include<iostream> #include<memory> using namespace std; class Student{public:Student(int index):_index(index){cout<<"Student"<<_index<<" constructor"<<endl;};~Student(){cout<<"Student"<<_index<<" destructor"<<endl;}private:int _index; };int main() {auto_ptr<Student> ptr1(new Student(1));auto_ptr<Student> ptr2(new Student(2));ptr2 = ptr1 ; //ptr2's object will release cout<<"over"<<endl;return 0; }------------------ output: Student1 constructor Student2 constructor Student2 destructor over Student1 destructor
缺陷
由於auto_ptr本身就涵蓋擁有權,如果無意去轉換擁有權,絕對不要在參數中使用auto_ptr,也不要另auto_ptr作為返回值,否則會有很大的災難。以下是個範例
#include<iostream> using namespace std; void bad_print(auto_ptr<int> p) {if(p.get()==NULL){cout<<"NULL"<<endl;}elsecout<<*p<<endl;} int main() {auto_ptr<int> ptr(new int);*ptr=123;bad_print(ptr);*ptr=456;return 0; }------------- output: 123 Segmentation fault (core dumped)
因為在參數中,使用了auto_ptr,所以當呼叫此function的時候,便會把所有權轉移到function中的臨時變數,然後當function結束後,
這個區域的臨時變數又會銷毀,而在main中的ptr,因為呼叫function後擁有權轉移,所以第二次執行賦值的動作,就會出現runtime error了,
因為此時ptr並沒有任何指向任何物件,所以導致此崩壞行為。
在這種情況下,我們可以考慮採用pass by reference的方式來傳遞變數,可惜對於auto_ptr來說反而會製造更多麻煩,更難去掌握擁有權轉移的順序,
因此能避免就盡量避免使用auto_ptr跟pass by reference。
如果今天真的有要當參數傳入的需求,這時候可以使用constant reference,如此一來可以使得auot_ptrs本身無法轉移所有權。
以下的例子就會編譯錯誤,可提醒設計師轉移權的問題。與一般不同的是,這邊的const代表的並不是不能修改指標所擁有的物件,而是不能更改
auto_ptr的擁有權,更像是T* const ptr;
#include<iostream> using namespace std; void bad_print(const auto_ptr<int> p) {if(p.get()==NULL){cout<<"NULL"<<endl;}elsecout<<*p<<endl; } int main() {const auto_ptr<int> p(new int); *p = 123; bad_print(p); //COMPILE TIME ERROR *p = 456;return 0; }
總結
auto_ptrs之間不能共享擁有權
auto_ptr間沒辦法同時擁有一個物件,因此當把兩個auto_ptr指向對方時,就會使得本來的一方釋放其所擁有的物件,之後若是再透過該指標去操作,就會出現錯誤。
並不存在針對array設計的auto_ptr。
auto_ptr的內部設計是delete,而非delete[],所以不可以指向array。
auto_ptr並非萬能指標。
由於auto_ptr並非一個計數型指標(或者是上限為一的計數型指標),因此在使用上有非常多的限制,如果設計師沒有完全瞭解其特性,很容易就會讓程式出錯。
千萬別在STL 容器中使用auto_ptr。
因為STL標準規定,C++標準容器容易必須要符合"copy-constructible" 跟 "assignable." ,亦即容器中的元素必須都要能夠被複製跟賦值,然而auto_ptr的特性並不相容上述行為,所以切忌使用,否則容易出錯。
淺談auto_ptr相关推荐
- 淺談 Java VM 發展
標題:淺談 Java VM 發展 作者:Jim Huang (黃敬群) 版權宣告:允許在保留作者.出處,以及本宣告的前提下,以任何人類可讀之形式 自由散佈 最後更新:Apr 16, ...
- [修練營ASP.NET]淺談多層式架構 (Multi Tiers)
從需求談起 我們舉個小例子來理解一般的方式與多層的方式有何不同 假設:我需要顯示最近三個月內,所有營業員的銷售金額成績排名 一般的做法: 在一個畫面中,拉個GridView,一個SqlDataSouc ...
- 修練營ASP.NET]淺談多層式架構 (Multi Tiers)
從需求談起 我們舉個小例子來理解一般的方式與多層的方式有何不同 假設:我需要顯示最近三個月內,所有營業員的銷售金額成績排名 一般的做法: 在一個畫面中,拉個GridView,一個SqlDataSouc ...
- 淺談Raid Cache Memory上應用的問題和實踐
$1, Raid和Cache Memory 通常,出於二個目標:安全和性能,我們在生產環境的服務器上會設置Raid功能.最常見的場景是,我們會由於安全性的考慮將磁盤設置成Raid 1 或Raid 5. ...
- oracle undo head,淺談Oracle的undo管理
1.什么是undo 當我們對數據執行修改操作時,數據庫會生成undo 信息,這樣一旦執行的事務或語句由於某種原因失敗,或者發出一條ROLLBACK 語句請求回滾,就可以利用這些undo信息將數據放回到 ...
- Install gevent in AIX with gcc
为什么80%的码农都做不了架构师?>>> greenlet Download greenlet-0.4.1.zip from https://github.com/python ...
- 讲解开源项目:用 Python 生成有“灵魂”的二维码
本文作者:HelloGitHub-LITTLECHIEH 这是 HelloGitHub 推出的<讲解开源项目>系列,今天给大家推荐一个 Python 开源生成二维码的项目--qrcode ...
- surfaceflinger类图
frameworks/base/libs/ui 和 frameworks/base/libs/surfaceflinger ISurface 定义了基础的Surface接口,供图形系统客户端 (应用) ...
- 浅谈PHP与Java之Web开发整合技术
淺談PHP與Java之Web開發整合技術 鄭哲聖郑哲圣 前言 PHP為語法簡單的腳本語言,可以做為HTML的嵌入型語言,而且與Apache網頁伺服器搭配的設定容易.效能亦高. 前言 ...
- 桌球歷史:削球、快攻、弧圈球
專欄 [乒乓邦]桌球歷史:削球.快攻.弧圈球 PingPong.Bang | 乒乓邦 | 2015/04/18 | 人氣 2981 0 收藏此文0 A+A- 江山代有才人出,各領風騷數百年.回顧桌球 ...
最新文章
- ORB_SLAM2程序入口(System.cc)
- 欧卡智舶发布全球首个城市内河无人驾驶数据集!
- python爬取站长素材网页图片保存到ppt中
- Python 集合的定义以及常用运算及函数
- 089_DOM节点动态创建、添加和删除
- 使WEBBROWSER 可编辑
- Ubuntu18.04 给整个目录及子目录赋权限
- 附件文件无法保存到服务器,可能是目录属性设置问题,请与管理员联系,Discuz不能上传过大文件的解决办法...
- python 内存分析_python内存管理分析
- Chrome本地安装vue-devtools调试工具的问题
- set的用法及短语_专升本英语易考短语搭配+常考句型
- SpringBoot学习笔记(2) Spring Boot的一些配置
- 修改cas5成功html文件,手把手教Apereo CAS5.2.3 Server端 增量开发 自定义登录页,增加验证码,注册,修改密码等功能的方式...
- lwip路由实现_TCP控制块《LwIP协议栈源码详解——TCP/IP协议的实现》
- python读取大智慧数据_大智慧数据格式
- 职称计算机考试常用的命令,职称计算机考试VisualFoxPro常用命令
- Java爆笑梗,jvav是什么鬼!盘点那些迷你小学生中那些笑死人的梗
- java CGLIB动态代理
- 泵站和水闸无人值守系统
- 程序员延寿指南 | A programmer's guide to live longer
热门文章
- 分别使用多线程\多进程\协程+paramiko在华为交换机批量快速进行配置(eNSP模拟器)
- HCIE Security 2020.12.04面试战报
- C++ machine code与随机数 进阶习题
- C语言qsort和C++sort的用法小结和区别比较
- HDOJ-2091 空心三角形 C语言
- Cinema 4D* 中令人惊叹的体积效果
- js学习(六)- js对象创建
- ORCU浅析之安装和作用
- Android使用AsyncTask设置请求超时的注意事项
- opencv threshold_OpenCV致幻