C++的未來和指針

本文由 伯樂在線 - 周昌鴻 翻譯自 Meeting C++。歡迎加入 技術翻譯小組。轉載請參見文章末尾處的要求。

上周Meeting C++2013結束后,我對C++思考了很多,有一些內容和指針有關。在C++ 11中只對指針進行了小量的更新(引入了nullptr),不過過去幾年中,C++中指針的語義和用法卻發生了很多變化。

首先,我們從指針的原始意義開始,C++11中簡單如type* pt = nullptr; 這里的指針是C語言中的核心概念,指針并不是C++發明的,據我所知也不是C發明的。但是C規范中定義了指針,并給出了在C和C++中使用指針的指導。事實上,指針是一個變量,它存儲的值是內存中的一個地址。如果你對指針進行解引用操作,就能訪問指針指向的變量。指針實際上是一個基礎變量,它不知道它所指向的值是否有效,也不能感知其指向的值是否無效。在C語言中,一個指針指向0,說明其不指向任何值,因此也不具有效的值。所有其他指針都應該指向內存中有意義的地址,但實際上,有些指針沒有正確的初始化,或者干脆越出了應有的范圍。

在C++11中,將指針正確初始化為0的方法是使用關鍵字nullptr。這讓計算機知道該指針當前為空。另外,還有一種常用的方式是將0定義為NULL或者其他定義或聲明。C++11中使用nullptr統一了這種方式。C++中還引入了引用,它看起來像是變量的別名,其優勢是使用引用的時候必須先初始化,因此,在引用生命周期起始時需要指向一個有效地址。不過,引用也只是指針的解引用,所以,一旦其引用的變量作用范圍結束,其引用也無效了,使用指針時,你可以將指針置為0,但是針對引用卻不能這么做。

但是在C++11和在C++11標準之前,一些事情發生了變化,指針是語言的核心概念,但是你在現代化的C++代碼和函數庫中卻很少看到它們。遠在C++11之前,boost創建了一系列非常有用的智能指針類,針對指針進行了封裝,對其核心機制通過操作符重載。智能指針本身不是一個指針,而是一個棧上的變量或對象成員。智能指針使用了RAII來解決指針的一些問題,這并不是指針的職責。當在椎中分配內存時,new返回了指向該部分內存的地址,所以每分配一塊動態內存,就需要使用一個指針,相當于創建對象的一個操作句柄。但是指針僅僅是一個簡單的變量,不知道變量的擁有關系,也不能自動釋放堆上的內存空間。智能指針擔當了這一角色,擁有指針并在變量超出作用域時自動管理其堆上的值。在棧上的值意味著,一旦相應的棧被銷毀,其管理的堆上的值會被自動釋放,即使是在發生異常的情況下。

過去的一些年,C++出現了一些不同風格的使用,從使用類的C及大量使用指針,到類似我想Widget和QT這樣面向對象的框架。在過去5-10年中的形成的一種新樣式被認為是現代C++,一種趨向盡力發掘語言本身擴展能力,并試圖找到不同特性針對不同場合的應用。值得注意的是boost在這一趨勢中起到了引領風范的C++框架。C++標準在設計其標準庫時也借鑒了這一點。與此同時,值語義變得流行起來,并且與move語義成為未來C++一個關鍵點。來自Tony van Eerds在Meeting C++的一份備忘幻燈片引起了我對指針的思考。它有兩列,一個代表引用語義,一個代表值語義,以及其朗朗上口的主題詞:

哦,不!使用指針 vs 哦,不要使用指針!

所以,在C++11或者后續的C++14,使用值語義的趨勢蓋過了使用指針。指針在取后臺還是工作著,不過在新的C++14中,new和delete都將不提倡直接使用,new被抽象化為make_shared/make_unique。其內部使用了new,但是返回一個智能指針。shared_ptr 和 unique_ptr都表現為值語義類型。智能指針同樣在其作用域結束時使用delete釋放內存。這讓我思考,C++中的指針是不是都可以填充不同的“角色”,或者被替換掉。

繼承和虛擬函數

指針一個非常重要的用途是在繼承中使用指針來指向一系列擁有相同接口的類型值。我想用Shape例子來闡明這一點,這里有一個基類Shape,同時其含有一個虛擬函數叫area的方法。同時,它還有幾個派生類叫Rectange,Cirecle和Triangle。現在,有一個指針容器(比如:std::vector<Shape*>)來容納指向不同形狀的對象指針,每個對象都有自己的計算面積方法。這是C++中最常用指針的方式,尤其是在面向對象時。現在,好消息是,這里同樣支持使用智能指針,當其使用這些智能指針時,內部會進行訪問指針。Boost中甚至還有一個指針容器,能在清空容器時自動釋放其中的智能指針元素。

現在考慮虛函數調用(這雖然不和指針有直接聯系),虛函數調用通常會有點點慢,同時也不容易編譯器針對其進行優化。所以,如果其類型在運行時是可知的,就可以使用靜態分發或者編譯器多態性來正確調用相應的虛函數方法,而不是在運行時使用虛函數指針。作為一種模式被叫做CRTP,已經實現了這一方式。最近的研究顯示,這在gcc4.8中可以提高性能。有趣的是,通常情況下使用gcc4.9,優化器可以針對動態分發進行更進一步的優化。還是讓我們繼續回到指針。

不確定指針

有時候指針被用于有一系列可選值作為參數或者返回不確定的函數中,通常都默認為0,用戶可以選擇傳遞一個有效的指針給該函數。或者在返回的情況下,函數返回一個空指針表示執行失敗。對于錯誤情景,現代C++中常使用異常,但是在有些嵌入式平臺上不能工作,因此,(返回0)在C++的一些場合中也是一個有效的使用方式。同樣的,這里也可以使用智能指針,智能指針可以扮演指針的操作句柄。不過常常會導致堆上內存開銷(使用堆),或者并沒有替代不確定的角色。這需要使用一個可選值類型來代替,用于確定其存儲的值是否有效。Boost庫有一個boost::optional來表示可選值類型。因此,可以考慮在C++14中引入有一個類似的可選類型。所以,現在std::optional會被移入到技術預覽版(TS)中,將來會變成C++14或者C++1y的一部分。

當前的標準庫中已經使用了一些可選類型,比如std::set::insert會返回一個pair<iterator,bool>類型,其第二個參數表示請求值是否插入到set容器中。容器通常返回尾迭代器來表示無效,但是如果要求返還一個值時,這個角色過去通常都是用指針來表示,指針為0表示函數執行失敗,因此這里的指針可以被可選類型替代:

1
2
3
4
5
optional<MyValue> ov = queryValue(42);
if(ov)
??cout << *ov;
else
??cerr << "value could not be retrieved";

因此,可選類型和智能指針類型替代了指針的一部分語義,填充了其角色。但是它們是值語義,并大部分都在棧上使用。

有效的指針

在寫作我對C++指針用法的思考時,我主要關注于那些指針可以被其他(比如:智能指針和可選類型等)替換的場景,但是低估了實際上有些場景指針仍然有用。感謝來自reddit,email和社交媒體的一些反饋。

非擁有者指針就是這樣一個例子,這里未來的幾年還是需要使用指針。shard_ptr有對應的weak_ptr,但是unique_ptr沒有對應的伙伴。這里就需要使用非擁有者原始指針。比如,在一個由父和子對象構成的樹或者圖中。但是,未來C++中會新增exempt_ptr來代替。

在處理函數中的傳遞的值時,指針還是具有用處的,Herb Sutter寫了一篇非常好的文章:《GotW about this in May》。Eric Niebler 在他的Meeting C++會議的筆記中也談及了,同時移動語義會影響你應該如何在函數中傳遞或者返回值。

Category

C++11

Input Arguments

?

small/POD/sink

pass by value

all others

pass by const ref

Output

return by value

Input/Output

non const ref / stateful Algorithm Object

這個表格來自 Eric Nieblers 的筆記, 請看幻燈片中的16/31 (建議你閱讀所有的幻燈片)

Eric Niebler說過,在能使用移動語義時盡可能使用移動語義。一個可選參數為例,vector::emplace_back接收一個參數,當其只是將把元素移動到適當位置,這時你應得使用移動語義。一些輸出參數返回一個值,編譯器可以使用移動語義或者CopyEllision(拷貝去除)的優化技術。針對一些以對象為輸入/輸出參數,非常引用也是可選擇性優化的,但是Eric在他的筆記中指出:對象算法的狀態在構造函數中應使用槽參數。

在傳遞常量(非常量)引用時,指針可以做同樣的事情,不過有些不同,你需要對指針測試其是否為空。我個人更喜歡在函數/方法或者構造函數時傳遞引用而不是指針。

指針計算

之前我提到過,從我個人的觀點,指針只是一個普通的變量,其值指向一個地址,或者更精確地說,是其指向值得一個地址號碼。這個地址號碼可以被復制,你可以對其進行加或減法操作。這常常用于遍歷數組或者計算兩個指針的的距離,這在使用數組時很有用。這里對數組的便利其實就是迭代器,所以,在實際代碼時,指針可以代替迭代器使用。但是,從我多年C++開發經驗來看,我幾乎沒有用到針對指針的計算操作。而且在C++中,指針的計算已經有了非常好的抽象。我的觀點是,理解指針計算是重要的,這有助于理解代碼中指針的具體作用。

再見,指針?

理論上,C++可以不使用指針,但是由于指針是C/C++語言的核心概念,指針本身仍然會繼續存在。但是它的角色會變更,在你使用C++時,你不再需要考慮指針。隨著C++的繼續發展,C++11和C++14朝著更抽象,對開發者更友好的方向發展。使用智能指針和可選類型,指針要么被封裝從而更適用安全的值類型,要么完全被它們替代掉。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/447484.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/447484.shtml
英文地址,請注明出處:http://en.pswp.cn/news/447484.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Java魔法類:Unsafe應用解析

Unsafe是位于sun.misc包下的一個類&#xff0c;主要提供一些用于執行低級別、不安全操作的方法&#xff0c;如直接訪問系統內存資源、自主管理內存資源等&#xff0c;這些方法在提升Java運行效率、增強Java語言底層資源操作能力方面起到了很大的作用。但由于Unsafe類使Java語言…

AMD迎接變革:加速OpenCL的未來

摘要&#xff1a;AMD在北京中關村皇冠假日酒店舉辦了以"迎接變革&#xff1a;加速進入OpenCL 的未來"為主題的技術培訓。AMD Firepro顯卡資深產品經理JC、OpenCL資深講師陸教授、謝博士與大家探討OpenCL技術將如何引領變革、鑄造計算新紀元。 4月11日&#xff0c;AM…

JAVA中神奇的雙刃劍--Unsafe

參考資料&#xff1a; 前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 Java魔法類&#xff1a;sun.misc.Unsafe在openjdk8下看Unsafe源碼 Unsafe介紹 在Oracle的Jdk8無法獲取到sun.misc…

讓AMD在中國發聲 APU14技術創新大會首次在華召開

今日&#xff0c;AMD一年一度的開發者峰會“APU2014”在北京拉開帷幕&#xff0c;這也是AMD首次在美國之外的城市舉辦該活動。AMD全球副總裁、大中華區董事總經理潘曉明表示&#xff0c;大中華區是AMD重要的戰略區域&#xff0c;AMD希望通過本次活動在中國制造巨大的聲音&#…

Python已成美國頂尖高校中最受歡迎的入門編程語言

在最近的一份調查中顯示&#xff0c;美國top高校中&#xff0c;Python已經成為教授計算機科學入門課程方面最受歡迎的語言。其中Top10 CS系中有8所使用Python&#xff0c;Top39 CS系中有24所&#xff0c;在入門課程中教授Python&#xff0c;可見其實用性的認可度很高。在我寫下…

源碼閱讀 AtomicInteger

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 AtomicInteger 原子整數 可以原子更新的int值。 用于原子遞增計數器等應用程序中&#xff0c;不能用作java.lang.Integer的替換。 擴展…

A飯福利,AMD Mantle API獲眾多游戲開發商青睞!

摘要&#xff1a;Videocardz整理了一份2014年—2015年支持AMD Mantle游戲列表&#xff0c;并公布了游戲開發商及游戲引擎的名稱。已發布且支持Mantle的游戲主要有《戰地4》、《神偷4》、《植物大戰僵尸&#xff1a;花園戰爭》以及《狙擊精英3》這四款。 現如今&#xff0c;越來…

linux 安裝 maven 、解決:bash: mvn: command not found

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 1、安裝 wget 命令: yum -y install wget 2、下載maven安裝包 wget http://mirrors.cnnic.cn/apache/maven/maven-3/3.5.4/binaries/a…

軟件工程師必學的9件事

本文是html5tricks原創翻譯&#xff0c;轉載請看清文末的轉載要求&#xff0c;謝謝合作&#xff01; 三年前&#xff0c;我還在巴塞羅那的神經科學實驗室工作&#xff0c;忙著研究腦電波、教授心理學上的認知系統課程。而今天&#xff0c;我以設計和寫軟件為生。 你或許會滿頭…

Linux 的 chmod 命令,對一個目錄及其子目錄所有文件添加權限

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 對一個目錄及其子目錄所有文件添加權限 命令&#xff1a; chmod 777 -R ./html 給予html目錄下可讀可寫可操作權限。 或者 chmod -R…

Linux 下壓縮與解壓.zip 和 .rar

1)對于.ziplinux下提供了zip和unzip程序&#xff0c;zip是壓縮程序&#xff0c;unzip是解壓程序。它們的參數選項很多&#xff0c;可用命令zip -help和unzip -help查看&#xff0c;這里只做簡單介紹&#xff0c;舉例說明一下其用法&#xff1a;# zip test.zip test.jpg test.pn…

優秀的程序員VS糟糕的程序員

優秀的程序員和一般的程序員差別在哪里&#xff1f;怎么才能成為優秀的程序員&#xff1f;我們選擇了這個職業就要把他做好&#xff01; 優秀的程序員&#xff1a; 1、邏輯能力很強&#xff0c;這也是解決問題的關鍵。 2、分析能力。可以很好的解決復雜問題。 3、事情做得專…

圖解 Java 常用數據結構

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 最近在整理數據結構方面的知識, 系統化看了下Java中常用數據結構, 突發奇想用動畫來繪制數據流轉過程. 主要基于jdk8, 可能會有些特性與…

程序員生存定律--使人生永動的勢能

程序員生存定律這系列的目錄在這里&#xff1a;程序員生存定律--目錄 喜歡從頭瞄的&#xff0c;可以移步。 ------------------------------------------------------------------------------- 這篇說的是精神&#xff0c;比較務虛&#xff0c;不感興趣的可以略過。 在國內有…

int 和 Integer 的區別

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 1、Integer是int的包裝類&#xff0c;int則是java的一種基本數據類型 2、Integer變量必須實例化后才能使用&#xff0c;而int變量不需要…

度量術語之二:應用類和開發類生產率(實際度量案例)

一個令人震驚的事實是連生產率這種常見度量數據都沒有一個簡單的定義。連我們日常經常用到的公式&#xff1a;生產率工作產品/工作量&#xff08;工作產品可以是代碼行&#xff0c;功能點&#xff0c;也可以是任何可以計數的東西&#xff0c;比如文檔頁數&#xff09;都是錯誤的…

注解 @ModelAttribute 運用詳細介紹

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。1.ModelAttribute注釋方法   例子&#xff08;1&#xff09;&#xff0c;&#xff08;2&#xff09;&#xff0c;&#xff08;3&#x…

編程語言 IDE 對比

IDE是集成開發環境的英文縮寫&#xff0c;所謂集成開發環境&#xff0c;就是將你在開發過程中所需要的工具或功能集成到了一起&#xff0c;比如代碼編寫、分析、編譯、調試等功能&#xff0c;從而最大化地提高開發者的工作效率。每種編程語言都有一些特定的IDE&#xff0c;本文…

強制更新 maven 緩存

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 mvn dependency:purge-local-repository

程序員為什么那么難升職

一個有趣的現象是老程序員很難升職&#xff0c;如果你因為3K工資太低而要辭掉工作&#xff0c;你的上司寧可去外面找一個5K工資的新人&#xff0c;也不會來挽留你。那么程序員為什么那么難升職&#xff0c;這里總結了幾點。你上司的問題你晉升困難&#xff0c;最大的主觀原因在…