指標
引用與指標
引用 & | 指標 * |
---|---|
必須初始化 | 可以不初始化 |
不能為空 | 可以為空 |
不能更換目標 | 可以更換目標 |
初始化案例
int &r; //不合法,沒有初始化引用
int *p; //合法,但p為野指標,使用需要小心
(1)是否需要初始化
由於引用不能為空,所以我們在使用引用的時候不需要測試其合法性,而在使用指標的時候需要首先判斷指標是否為空指標,否則可能會引起程式崩潰。
進行檢查
void test_P(int *p){
if(p !=NULL)
*p=3;
return;
}
void test_r(int &r){
r=3;
return;
]}
(2)指向目標是否能更改
指標可以隨時改變指向,但是引用只能指向初始化時指向的物件,無法改變
指向目標
int a = 1;
int b = 2;
int &r = a; //初始化引用r指向變數a
int *p = &a; //初始化指標p指向變數a
p = &b; //指標p指向了變數b
r = b; //引用r依然指向a,但a的值變成了b
引用
左值引用
常規引用,一般表示物件的身份。
右值引用
右值引用就是必須繫結到右值(一個臨時物件、將要銷燬的物件)的引用,一般表示物件的值。
右值引用可實現轉移語義(Move Sementics)和精確傳遞(Perfect Forwarding),它的主要目的有兩個方面:
消除兩個物件互動時不必要的物件複製,節省運算儲存資源,提高效率。
能夠更簡潔明確地定義泛型函式。
引用摺疊
X& &
、X& &&
、X&& &
可摺疊成 X&
X&& &&
可摺疊成 X&&
C++的引用在減少了程式設計師自由度的同時提升了記憶體操作的安全性和語義的優美性。比如引用強制要求必須初始化,可以讓我們在使用引用的時候不用再去判斷引用是否為空,讓程式碼更加簡潔優美,避免了指標滿天飛的情形。除了這種場景之外引用還用於如下兩個場景
引用型引數
一般我們使用const reference引數作為只讀形參,這種情況下既可以避免引數複製還可以獲得與傳值引數一樣的呼叫方式。
引用型引數
void test(const vector<int> &data)
{
//...
}
int main()
{
vector<int> data{1,2,3,4,5,6,7,8};
test(data);
}
引用返回值
C++提供了過載運算子的功能,我們在過載某些運算子的時候,使用引用型返回值可以獲得跟該運算子原來語法相同的呼叫方式,保持了運算子語義的一致性。一個例子就是operator []運算子,這個運算子一般需要返回一個引用物件,才能正確的被修改。
引用返回值
vector<int> v(10);
v[5] = 10; //[]運算子返回引用,然後vector對應元素才能被修改
//如果[]運算子不返回引用而是指標的話,賦值語句則需要這樣寫
*v[5] = 10; //這種書寫方式,完全不符合我們對[]呼叫的認知,容易產生誤解
指標
函式指標
函式指標的定義
int (*pf)(int,int);
typedef int (*PF)(int,int);
函式指標使用
/**
* @file func_pointer.cpp
* @brief 函式指標的使用!
*/
#include <iostream>
using namespace std;
/**
* @brief
* 定義了一個變數pFun,這個變數是個指標,指向返回值為空和引數為int的函式的指標!
*/
void (*pFun)(int);
/**
* @brief 代表一種新型別,不是變數!所以與上述的pFun不一樣!
*/
typedef void (*func)(void);
void myfunc(void) { cout << "asda" << endl; }
void glFun(int a) { cout << a << endl; }
int main() {
func pfun = myfunc; /*賦值*/
pfun(); /*呼叫*/
pFun = glFun;
(*pFun)(2);
}