主頁 > 軟體設計 > C++編程經驗(7):delete之后到底要不要置空?

C++編程經驗(7):delete之后到底要不要置空?

2021-08-11 07:50:04 軟體設計

說來慚愧,是因為我忘了到底要怎么正確的delete,然后查到了這個話題,然后見識了一場大佬們的討論,

辯題:C++ 里 delete 指標兩次會怎么樣?(后來被扭曲為:C++ delete之后到底要不要置空)
正方:C++ delete之后當然要置空了
反方:C++ delete之后不應該置空掉


首先是置空派的選手上場:
一直以來都是這么寫的,書上、老師都是這么說的,

接著是不置空派選手上場:
一派胡言!
很怕這種觀念又成為了某種教條,

作者:丁冬 鏈接:https://www.zhihu.com/question/38998078/answer/79321819 來源:知乎
著作權歸作者所有,商業轉載請聯系作者獲得授權,非商業轉載請注明出處,

舉個例子:

~scoped_ptr() // never throws
{
#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
    boost::sp_scalar_destructor_hook( px );
#endif
    boost::checked_delete( px );
}

這是boost::scoped_ptr的實作,checked_delete只是增加了對incomplete type的檢查:template inline void checked_delete(T * x)

{
    // intentionally complex - simplification causes regressions
    typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];
    (void) sizeof(type_must_be_complete);
    delete x;
}

可以看見boost::scoped_ptr根本沒有對delete后的指標進行置空,如果boost::scoped_ptr真的把其持有的指標置空,反而可能掩蓋類似這樣的錯誤

boost::scoped_ptr<MyClass> sp(new MyClass);
// some code
sp.~boost::scoped_ptr<MyClass>();
// by the end of the scope, sp counld be destructed again

按理說任何一個非trivial的有效物件被多次析構都應該是明顯的邏輯錯誤,構造和析構必須是一一對應的,這樣的錯誤也許一般用戶很少遇到,因為顯式呼叫解構式往往都是庫作者干的事,但這不代表這種奇怪的錯誤完全不會發生,很不幸的是,對于這種邏輯錯誤開發者往往沒有特別好的手段可以規避掉,二次delete一個懸垂指標行為是未定義的,也就是說錯誤是有可能被隱藏的,但是如果boost::scoped_ptr幫你把px給置空了,結果只會更糟糕:這下錯誤鐵定是被徹底隱藏了,根本別想找輕易到,沒有置空的話好歹有一定概率會崩潰給你看呢,當然“delete后置空指標”這種教條能流傳這么久,肯定是有它的道理的,

關于到底什么時候需要置空指標,關鍵之處在于搞清楚置空指標到底解決了什么問題
先來理一下nullptr和野指標/懸垂指標的區別:

解參考:
nullptr:未定義
野指標/懸垂指標:未定義

delete nullptr:良好定義,delete什么也不用做
野指標/懸垂指標:未定義

值:nullptr:明確
野指標/懸垂指標:未定義,無法確定

可以發現nullptr最大的優勢在于值是明確的,也就是說分辨一個指標是不是nullptr比分辨一個指標是不是野指標/懸垂指標要容易得多,那delete后置空指標的最大價值就在于明確資源當前狀態,你想判斷一個資源是否有效時,你當然沒法直接跑去看這個資源在不在,而是得詢問資源的持有者是否仍然持有這個資源,如果所有被delete的指標都被置為nullptr,以后再去訪問這個指標的時候,我們可以通過其與nullptr的比較輕松判斷出資源是否已經被delete,當然,這個優勢基于一個重要的前提:在設計上允許在資源已經失效的情況下,資源的持有者保持有效,如果資源的持有者也被干掉了,那即使你想通過nullptr判斷資源是否存在,你也找不到持有資源的指標進行比較,至此,我們至少可以得出一個結論,如果物件是和持有其的指標一同銷毀的,那置空指標就是脫褲子放屁,這個結論還可以引申一下:如果資源與其所有的持有者(含弱參考)一同被銷毀,那即將消亡的持有者們都沒有必要,也沒有能力為資源的后續狀態負責,/********************************/其實delete/free后置空這樣的教條已經幾乎走上了和goto-label之流一樣的道路,很多人看到了前輩們留下的經驗之談,妄圖死記住口口相傳的best-practice,卻忘記了前因后果,


接下來插入一則訊息,中立派登場:

試一試怎么了,死的是程式,又不會是系統、電腦、或開發者,以后路還長著,連這個最簡單最基本的都不敢試的話,以后會遇到更多麻煩,另一方面,你不能通過一次試的結果得出結論,因為那只能說明在特定編譯器、特定crt下的結果,原理上你得知道delete是不改變指標值的,所以第二次delete的時候,行為未定義,什么事情都可能發生,好習慣永遠是delete之后立刻賦nullptr,這樣即便意外第二次delete了,也沒關系,因為delete nullptr是有良好定義的,

作者:叛逆者
鏈接:https://www.zhihu.com/question/38998078/answer/79188320
來源:知乎 著作權歸作者所有,商業轉載請聯系作者獲得授權,非商業轉載請注明出處,

我就是中立派的,我也去試了一下,結果我的VS給搞崩了,,,,
然后我又換到g++去試,最后發現:
請添加圖片描述

該報錯的它就是要報錯,攔不住的,
就算二次置空了又怎么樣?

這里我要講一下,delete回收的是指標指向的那塊記憶體,而上面的p、q指向的是同一塊記憶體,


接下來又來了個正方觀點,我覺得他這個觀點挺烏龍的,因為我上面那個代碼就是受他的啟發:

作者:二律背反
鏈接:https://www.zhihu.com/question/38998078/answer/79157526
來源:知乎 著作權歸作者所有,商業轉載請聯系作者獲得授權,非商業轉載請注明出處,

Why doesn’t delete zero out its operand?Consider

delete p;
// ...
delete p;

If the … part doesn’t touch p then the second “delete p;” is a serious error that a C++ implementation cannot effectively protect itself against (without unusual precautions). Since deleting a zero pointer is harmless by definition, a simple solution would be for “delete p;” to do a “p=0;” after it has done whatever else is required. However, C++ doesn’t guarantee that.One reason is that the operand of delete need not be an lvalue. Consider:

delete p+1;
delete f(x);

Here, the implementation of delete does not have a pointer to which it can assign zero. These examples may be rare, but they do imply that it is not possible to guarantee that any pointer to a deleted object is 0.'' A simpler way of bypassing thatrule’’ is to have two pointers to an object:

 T* p = new T;
	T* q = p;
	delete p;
	delete q;	// ouch!

C++ explicitly allows an implementation of delete to zero out an lvalue operand, and I had hoped that implementations would do that, but that idea doesn’t seem to have become popular with implementers.If you consider zeroing out pointers important, consider using a destroy function: template inline void destroy(T*& p) { delete p; p = 0; }
Consider this yet-another reason to minimize explicit use of new and delete by relying on standard library containers, handles, etc.Note that passing the pointer as a reference (to allow the pointer to be zero’d out) has the added benefit of preventing destroy() from being called for an rvalue:

   int* f();
	int* p;
	// ...
	destroy(f());	// error: trying to pass an rvalue by non-const reference
	destroy(p+1);	// error: trying to pass an rvalue by non-const reference

======================= c++ primer 4th edition ======================
5.11.6:After deleting a pointer, the pointer becomes what is referred to as a dangling pointer . A dangling pointer is one that refers to memory that once held an object but does so no longer. A dangling pointer can be the source of program errors that are difficult to detect. Setting the pointer to 0 after the object it refers to has been deleted makes it clear that the pointer points to no object.

我現在實在是不知道他到底要表達什么意思了,,,


好,反方大佬出場:

delete 之后賦值 nullptr 絕對是壞習慣,會掩蓋真實的錯誤,也不利于使用各種 memory checker 工具找出錯誤,類似的還有為了防止 double free 而在 free 之后賦值 NULL,一樣是錯誤的,在 C++ 里,任何資源釋放的操作都應該在解構式里進行,這樣只要管好物件生命期就不會有資源泄漏了,

作者:陳碩
鏈接:https://www.zhihu.com/question/38998078/answer/114314884
來源:知乎 著作權歸作者所有,商業轉載請聯系作者獲得授權,非商業轉載請注明出處,

是吧,大佬都這么說了,


又有反方大佬出場:

delete 后置為 nullptr 在 C++ 中一般是不必要的,因為 C++ 可以用 RAII 來管理記憶體,而解構式是被編譯器保證只執行一次的,
不過 free 后置為 NULL 在 C 中似乎常常是不可避免的,因為需要用 NULL 來判斷狀態,不然代碼就會寫得非常復雜,


最后呢,我的觀點:
關于到底什么時候需要置空指標,關鍵之處在于搞清楚置空指標到底解決了什么問題,
如果沒有必要,那就,放著唄,真錯了,錯了就是錯了,早點報出來早點解決掉,

此外,智能指標真的要去嘗試使用一下了,

精彩不容錯過:https://www.zhihu.com/question/38998078

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/292995.html

標籤:其他

上一篇:nginx問題的影響

下一篇:同樣是網頁前端小白你的頁面為什么更高級?

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more