日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

C++:传值与传址的区别以及引用的使用

發布時間:2023/11/27 生活经验 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++:传值与传址的区别以及引用的使用 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

使用指針的好處其一:指針復制成本低。

不使用指針的高成本:

#include<iostream>void fun(int x)
{}int main()
{int x=42;fun(x);//系統在調用的時候,會把x這個對象的內容復制到fun的這個形式參數里面,經過這樣的復制之后我們才能在fun函數里邊去使用x。
目前只是一個int型的x所以復制是很快的,如果是一個復雜的結構體,結構體里邊的東西很大的話}

如果定義了一個結構體,結構體里邊的內容很大,

#include<iostream>
struct str
{//此結構體包含很多的內容};
void fun(str param)
{}
int main()
{str x;fun(x);//調用的時候x會被復制到形式參數param里邊,整個復制的過程因為str非常大,所以要耗費非常多的計算資源。要耗費非常多的CPU來進行復制,同時在內存當中會搞兩塊,一塊來保存x一塊來保存param,這樣他的整個調用成本就很高了。更過分的是有的時候str是要求不支持復制的,比如說str他代表了一個文件,或者他代表了一種獨占性質的資源,我們就不能要求他進行復制,因為他復制兩份之后呢這兩份指向的就是同一份資源,這個資源是獨占的,基本上來說不能這樣做。所以如果str不支持復制的話,這樣操作就是不合理的,是非法的,因為str要求自己不能進行復制,但是在傳參的時候我強制要求他進行了復制,那么整個程序他就是崩潰的。此種情況我們就可以求助于指針。
}

使用指針的低成本:

(傳址實現在函數內部改變輸入參數的數值,這一點是普通的對象無法做到的)

指針是對對象的間接引用。

指針的尺寸是相同的,對象的尺寸是不同的,所以有的對象是比較長的有的對象是比較短的,尤其是那些我們自定義的對象他的大小是比較大的,大小比較大的話在進行復制的話那么他的成本會比較高。

#include<iostream>
struct Str
{//此結構體包含很多的內容};
void fun(Str* param)//1、傳入的是指針
{}
int main()
{Str x;//2、str可能很大或者不支持復制Str* p=&x;//3、str*就不一樣了,他的長度就是8個字節(在64位機上他就是8個字節),(無論Str有多大,Str*就是8個字節)對這8個自己進行復制的話基本來講不會占多少的時間,其次即使Str不支持復制的話,Str*是支持復制的,我們的指針內部存的是地址,那么地址它就是一個數據,基本上來講完全是可以復制的,復制之后相當于param和p同時指向了x,這個是合法的,這樣我們就相對于來說使用了一個相對比較cheap的方法來調用函數,這一點就是引用指針的好處,復制成本低;但是指針存在一個問題就是讀寫成本比較高。fun(p);
}

要想對指針進行讀寫,通常來講需要解引用。解引用需要涉及到兩次的內存訪問,一次是訪問指針它內部保存的數據,也就是地址;另一次是根據獲取的數據也就是獲得的地址,再去訪問該地址獲取數據。所以基本上來講不管是讀還是寫成本都是比較高的。

指針如果作為函數的參數傳入的話,還有一個好處就是:我們可以去修改指針所指向的內部的值。這就是C或者C++中提到的概念:函數是傳值的還是傳址的。

使用指針的好處其二:可以去修改指針所指向的內部的值。

傳值:

void fun(int param)
{param=param+1;}
int main()
{int x=3;fun(x);//2、因為我們這個fun去調用的時候,其實是把這個3拷貝給了param,param是在內部進行了加1,這個param內部的任何修改實際上并不會影響到x,
因為x已經是復制過去了,這個就是C語言中最基本的傳值。我調用函數并不會改變我輸入參數的值。但是在一些情況下我們改變的是輸入參數的值。std::cout<<x<<std::endl;//1、調用完之后去打印x的話,打印出來的值仍然是3,并沒有加1
}

傳址:

在一些情況下希望去改變輸入參數的值:

void fun(int* param)
{*param=*param+1;//使用解引用的方式來進行加}
int main()
{int x=3;fun(&x);std::cout<<x<<std::endl;
}//或者寫做如下的形式
void fun(int* param)//3、那么param存的也是1234,換句話說param同時指向了x。
{param=param+1;//4、接下來對param進行解引用,無論是讀還是寫都是從x取來的,通過這樣的形式來改變相應的傳入參數的值。}
int main()
{int x=3;int* p=&x;//1、首先會把x的地址賦值給p,p里邊存的就是地址,比如0x1234fun(p);//2、在調用fun的時候param會是p的拷貝,std::cout<<x<<std::endl;
}--------------------------------------
//還可以將程序進行一個簡化
void fun(int* param)
{param=param+1;}
int main()
{int x=3;fun(&x);std::cout<<x<<std::endl;
}

所以引用指針就實現了對象的一個間接引用。通過這樣可以降低復制成本,實現傳址的這樣一個操作。

但是指針也存在他的問題:

(1)指向的內容可能并不是一個真正的對象。

void fun(int* param)
{param=param+1;}
int main()
{int x=3;int* p=&x;//指向的是一個對象int* p1;//在構造對象的時候,缺省初始化;這個時候可能指向的是一個非法的地址。int* p1=nullptr;//指向的是一個空對象。fun(p1);//這個時候的行為是不可控的。如何解決這個問題呢?就是采用引用。
}

引用

int& ref=val;//定義一個int類型的引用,叫做ref,他綁定到了int類型對象,叫做val;
int main()
{int x=3;int& ref=x;//定義一個int型的引用,指向xstd::cout<<ref<<'\n';//ref是x的別名,所以這里雖然打出來的是ref,他就相當于是說我要把x的值打出來,x的值是3,所以這里打出來是3。ref=ref+1;//ref本身是x的別名,所以相當于是把x的值拿出來加上1;std::cout<<x<<'\n';
}//因為ref是x的別名,所以我們在這里可以無差別的交換ref和x來使用。(從目前看來至少在在整個main函數里邊可以無差別的交換使用ref和x)
int main()
{int x=3;int& ref=x;std::cout<<ref<<'\n';ref=ref+1;std::cout<<x<<'\n';int* ptr=&x;int y=0;*ptr=y;//1、Ptr先解引用,然后再賦值,并沒有改變ptr的指向,改變的是ptr指向里邊的內容值。(改變指針指向的對象里面的值)ptr=&y;//2、改變的是ptr的指向。(改變指針本身所指向的內容)//3、但是引用只能有一層含義。改變他說綁定的這個對象所指向的內容。int y=0;ref=y;//把y的值賦予ref,因為ref是x的別名,就相當于他只是把y的值賦予了x,相當于執行完這句話之后ref還是綁定的x,同時x的值變成了0;//我們沒有辦法在代碼里實現一個功能,剛開始的時候ref綁定到x,之后呢ref綁定到另外的非x的其他的一個變量,這個是無法實現的。這個是引用她的一個限制,}

要避免下邊的非法的引用:

#include<iostream>
int& fun()
{int x;return x;
}
int main()
{int& res=fun();但是在main函數中調用你返回的是x的引用,相當于我這個引用指向了一個被銷毀的對象,所以實際上res就是一個非法的引用,接下來你對這個res無論是讀還是寫他的行為都是不確定的,}
//上述代碼是可以編譯通過的,但是他會出現一系列的warning。這就是我們構造了一個非法的引用。
引用出現非法的情況,首先我們先看看指針什么樣的情況會出現非法,指針出現非法的情況基本上來說就是我要解引用一個空指針,或者說我指針指向的位置本身就不是一個合法的對象的位置,這叫做指針的非法。
引用出現非法的情況:

引用出現非法的情況:

fun函數里邊我們相當于干了一件什么事情呢?如下解釋:
int& fun()
{int x;//1、聲明了一個變量x,return x;//2、接下來返回變量x。我們是通過引用的方式返回的。
}//將上邊函數進行細化的理解:
int& fun()
{int x;//1、聲明了一個變量x,int& ref=x; //2、等價于在這里定義了一個refreturn ref;//3、接下來返回ref
}//但是在C++里邊每一個對象都有一個生命周期的概念,x的生命周期是從int x定義開始到fun的這個大括號結束為止,所以也就是說如果fun返回了之后x也就不存在了,他可能就被系統銷毀了,但是在main函數中調用你返回的是x的引用,相當于我這個引用指向了一個被銷毀的對象,所以實際上res就是一個非法的引用,接下來你對這個res無論是讀還是寫他的行為都是不確定的,

int main()
{int x=3;int* ptr=&x;//構造一個指針,ptr指向x ;ptr是一個對象。int*&  ref=ptr;//構造ptr的引用//定義了一個指針的引用;按照從右到左的一個順序去解析這樣的一個聲明。前邊int*&是類型的部分,后邊ref是變量的部分,變量的名字叫ref,ref的類型是什么呢?首先從右往左看ref是一個&引用,他引用的是一個指針對象因為*代表指針,這個指針對象指向了一個int型的變量。所以說ref是綁定到了一個int型的指針上。
}

是否存在引用的引用呢?不存在。

??

?

總結

以上是生活随笔為你收集整理的C++:传值与传址的区别以及引用的使用的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。