c++11中新增了一種引用:所謂的「右值引用(rvalue reference)」,這種引用主要用於內建類。嚴格來說,當我們使用術語「引用(reference)」時,指的其實是「左值引用(lvalue reference)」
引用(reference)為物件起了另外乙個名字,引用型別引用(refers to)另外一種型別。通過將宣告符寫成&d的形式來定義引用型別,其中d是宣告的變數名:
int ival = 1024;
int &refval = ival; //refval指向ival(是ival的另乙個名字)
int &refval2; //報錯,引用必須被初始化
一般在初始化變數時,初始值會被拷貝到新建的物件中。然而定義引用時,程式把引用和它的初始值繫結在一起,而不是將初始值拷貝給引用。一旦初始化完成,引用將和它的初始值物件一直繫結在一起。因為無法令引用重新繫結到另外乙個物件,因此引用必須初始化。
引用即別名,引用並非物件,相反的,它只是為乙個已經存在的物件所起的另外乙個名字。
定義 了乙個引用後,對其進行的所有操作都是在與之繫結的物件上進行的:
refval = 2; //把2複製給refval指向的物件,此處即是賦給了ival
int ii = refval; //與ii = ival執行結果一樣。
為引用賦值,實際上是把值賦給了與引用繫結的物件。獲取引用的值,實際上是獲取了與引用繫結的物件的值。同理,以引用作為初始值,實際上是以與引用繫結的物件作為初始值。因為引用本身不是乙個物件,所以不能定義引用的引用。
允許在一條語句中定義多個引用,其中每個引用識別符號都必須以符號&開頭:
in i = 1024, i2 = 2048; //i和i2都是int
int &r = i, r2 = i2; //r是乙個引用,與i繫結在一起,r2是int
int i3 = 1024, &ri = i3; //i3是int, ri是乙個引用,與i3繫結在一起
int &r3 = i3, &r4 = i2; //r3和r4都是引用
注意,引用只能繫結在物件上,而不能與字面值或某個表示式的計算結果繫結在一起。
指標(pointer)是「指向(point to)」,與引用類似,指標也實現了對其他物件的間接訪問。然而指標與引用相比又有很多不同點。其一,指標本身就是乙個物件,允許對指標賦值和拷貝,而且在指標的生命週期內它可以先後指向幾個不同的物件。其二,指標無須在定義時賦初值。和其他內建型別一樣,在塊作用域內定義的指標如果沒有被初始化,也將擁有乙個不確定的值。
定義指標型別的方法將宣告符寫成 *d的形式,其中d是變數名。如果在一條語句中定義了幾個指標變數,每個變數前面都必須有符號*:
int *ip1, *ip2; // ip1和ip2都是指向int型物件的指標
double dp, *dp2; //dp2是指向double型物件的指標,dp是double型物件
指標存放某個物件的位址,要想獲取該位址,需要是取位址符(操作符&):
int ival = 42;
int *p = &ival;
因為在宣告語句中指標的型別實際上被用於指定它所指向物件的型別,所以二者必須匹配。如果指標指向了乙個其他型別的物件,對該物件的操作將發生錯誤。
指標的值(即位址)應屬下列4種狀態之一:
1.指向乙個物件。
2.指向緊鄰物件所佔空間的下乙個位置。
3.空指標,意味著指標沒有指向任何物件。
4.無效指標,也就是上述情況之外的其他值。
試圖拷貝或以其他方式無效指標的值都將引發錯誤。編譯器並不負責檢查此類錯誤,這一點和試圖使用未經初始化的變數是一樣的。訪問無效指標的後果無法預計,因此程式設計師必須清楚任意給定的指標是否有效。
如果指標指向了乙個物件,則允許使用解引用符(操作符*)來訪問物件。
對指標解引用會得到所指的物件,因此如果給解引用的結果複製,實際上也就是給指標所指的物件賦值: *p = 0;
note:解引用操作僅適用於那些確實指向了某個物件的有效指標。
空指標不指向任何物件,在試圖使用乙個指標之前**可以首先檢查它是否為空。以下列出幾個生成空指標的方法:
int *p1 = nullptr; //等價於int *p1 = 0; c++11新標準剛剛引入的一種方法
int *p2 = 0; //直接將p2初始化為字面常量0
//需要首先include cstdlib
int *p3 = null; //等價於int *p3 = 0;
當用到乙個預處理變數時,預處理器會自動地將它替換為實際值,因此用null初始化指標和用0初始化指標是一樣的。在新標準下,現在的c++程式最好使用nullptr,同時盡量避免使用null。
把int變數直接賦給指標是錯誤的操作,即使int變數的值恰好等於0也不行。
int zero = 0;
pi - zero; //錯誤:不能把int變數直接賦給指標
建議:初始化所有指標
使用未經初始化的指標是引發執行時錯誤的一大原因。
和其他變數一樣,訪問未經初始化的指標所引發的後果也是無法預計的。通常這一行為將造成程式崩潰,而且一旦崩潰,要想定位到出錯位置將是特別棘手的問題。
在大多數編譯器環境下,如果使用了未經初始化的指標,則該指標所佔記憶體空間的當前內容將被看作乙個位址值。訪問該指標,相當於去訪問乙個本不存在的位置上的本不存在的物件。糟糕的是,如果指標所佔記憶體空間恰好有內容,而這些內容又被當做了某個位址,我們就很難分清它到底是合法的還是非法的了。
因此建議初始化所有的指標,並且在可能的情況下,盡量等定義了物件之後再定義指向它的指標。如果實在不清楚指標應該指向何處,就把它初始化為nullptr或者0,這樣程式就能檢測並知道它沒有指向任何具體的物件。
指標和引用都能提供對其他物件的間接訪問,然而在具體實現細節上,二者有很大不同,其中最重要的一點就是引用本身並非乙個物件。一旦定義了引用,就無法令其再繫結到另外的物件,之後每次使用這個引用都是訪問它最初繫結的那個物件。
指標和它存放的位址之間就沒有這種限制了。和其他任何變數(只要不是引用)一樣,給指標賦值就是令它存放乙個新的位址,從而指向乙個新的物件。
有時候要想搞清楚一條賦值語句到底是改變了指標的值還是改變了指標所指物件的值不太容易,最好的辦法就是記住賦值永遠改變的是等號左側的物件。
自問他答:
c++中,0和null、nullptr 有什麼區別?
為什麼比起0和null,程式設計師更偏愛nullptr?
C 11之智慧型指標
c 98提供了了智慧型指標auto ptr,但c 11已將其摒棄,並提供了unique ptr和shared ptr。這三種智慧型指標模板都定義了類似指標的物件,可以將new獲得的位址賦給這種物件。當智慧型指標過期時,這些記憶體將自動被釋放。其基本用法如下 include include inclu...
c 11之智慧型指標
由於在c 中我們可以動態分配記憶體,但有時候我們會忘記用 delete或free釋放記憶體,就會導致記憶體洩露。所以c 11提供了智慧型指標這種東西 本文參考了知乎某知乎友的 比如下面這兩種情況 1 記憶體洩漏 str1所指的資源沒有被釋放 2 多重釋放,引起程式崩潰 可能平時都寫在乙個檔案不會忘記...
引數傳遞(引用,指標,值傳遞)C 11
c 中,函式的引數傳遞方式有值傳遞 位址傳遞。傳位址有指標和引用方式。在函式引數中,傳位址的理由有 1.使被調函式可以修改主調函式中的資料物件 2.傳位址可以減少資料拷貝,提高程式執行速度。那麼,何時使用值傳遞,何時使用位址傳遞 指標和引用 下面是一些寫 時會遇到的一些情況 如果要傳入函式的資料物件...