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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C++ : 构造函数,拷贝构造函数,移动构造函数,拷贝赋值运算符,移动赋值运算符应用场景

發(fā)布時(shí)間:2024/10/14 c/c++ 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++ : 构造函数,拷贝构造函数,移动构造函数,拷贝赋值运算符,移动赋值运算符应用场景 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

??構(gòu)造函數(shù),拷貝構(gòu)造函數(shù),移動(dòng)構(gòu)造函數(shù),拷貝賦值運(yùn)算符,移動(dòng)賦值運(yùn)算符應(yīng)用場景

#include <iostream> using namespace std;class ConstructTest{ public:ConstructTest(){cout<<"default Constructor\n";dim_=0;base_= nullptr;}; ~ConstructTest(){cout<<"Destructor:base "<<base_<<endl;if (base_ != nullptr){delete base_;}}ConstructTest(int dim){cout<<"Constructor with param"<<endl;dim_=dim;base_ = new int [dim];for (int i = 0; i < dim_; ++i) {*(base_ + i) = 0;}}ConstructTest (const ConstructTest & a){cout<<"copy Constructor"<<endl;dim_= a.dim_;base_ = new int [dim_];for (int i = 0; i < dim_; ++i) {*(base_ + i) = *(a.base_+i);}}ConstructTest& operator =(const ConstructTest & a){cout<<"copy assign "<<endl;dim_= a.dim_;base_ = new int [dim_];for (int i = 0; i < dim_; ++i) {*(base_ + i) = *(a.base_+i);}return *this;}ConstructTest& operator =( ConstructTest && a)noexcept{cout<<"moving copy assign "<<endl;//避免自己移動(dòng)自己if ( this == &a )return *this;delete base_;dim_ = a.dim_;base_ = a.base_;a.base_ = nullptr;return *this;}ConstructTest (ConstructTest && a) noexcept{cout<<"moving copy Constructor"<<endl;dim_ = a.dim_;base_ = a.base_;a.base_ = nullptr;}public:int dim_;int * base_; }; ConstructTest square(ConstructTest para){ConstructTest ret(para.dim_);ret.base_ = new int [para.dim_];for (int i = 0; i < para.dim_; ++i) {*(ret.base_+i) = *(para.base_+i) * (*(para.base_+i));}return ret; }int main(){ConstructTest c1(3);ConstructTest c2(c1);ConstructTest c4 ;c4=c2;cout<<"------------------------\n";ConstructTest c5 ;c5=square(c4);ConstructTest c6 = std::move(c5);cout<<"------------------------\n";ConstructTest c7;c7=ConstructTest();ConstructTest c8 = square(c7);ConstructTest c9 = ConstructTest();cout<<"<<<<<<finish >>>>>>>>\n"; }

C++ 和JAVA不一樣的是,C++ 區(qū)分了值類型和引用類型,不像JAVA一樣全是引用類型。創(chuàng)建對象 JAVA 用? <類名> 對象名= new ......? 而C++ 用 <類名> 對象名 就行 . 對于普通對象 用值傳遞的方式傳到形參,有一個(gè)隱式賦值的過程,此時(shí)調(diào)用的拷貝構(gòu)造函數(shù).以下的構(gòu)造函數(shù)使用場景:

構(gòu)造函數(shù)?: 創(chuàng)建對象時(shí),給對象初始化時(shí)調(diào)用。

拷貝(復(fù)制)構(gòu)造函數(shù): 利用相同的類對象給新對象初始化.時(shí)調(diào)用.

拷貝賦值運(yùn)算符 : 兩個(gè)舊對象之間的賦值。

所謂“移動(dòng)”就是把a(bǔ)的內(nèi)存資源挪為自用。

移動(dòng)構(gòu)造函數(shù): 在創(chuàng)建對象時(shí),用臨時(shí)對象初始化時(shí)調(diào)用。在返回值傳給返回值的副本時(shí)也會(huì)調(diào)用。

移動(dòng)賦值運(yùn)算符:?用臨時(shí)對象給舊對象賦值時(shí)調(diào)用。

?

我用的是CLION,在CMakeList.txt 加入如下代碼,來取消編譯器優(yōu)化

add_compile_options(-fno-elide-constructors)

在無編譯器優(yōu)化的情況下,輸出結(jié)果:

Constructor with param copy Constructor default Constructor copy assign ------------------------ default Constructor copy Constructor Constructor with param moving copy Constructor Destructor:base 0 moving copy assign Destructor:base 0 Destructor:base 0x3e1da8 ------------------------ moving copy Constructor ------------------------ default Constructor default Constructor moving copy assign Destructor:base 0 copy Constructor Constructor with param moving copy Constructor Destructor:base 0 moving copy Constructor Destructor:base 0 Destructor:base 0x3e1da8 default Constructor moving copy Constructor Destructor:base 0 <<<<<<finish >>>>>>>> Destructor:base 0 Destructor:base 0x3e1918 Destructor:base 0 Destructor:base 0x3e1dd8 Destructor:base 0 Destructor:base 0x3e1d90 Destructor:base 0x3e1d78 Destructor:base 0x3e1d60Process finished with exit code 0

在main函數(shù)第一到第四行中,展示了構(gòu)造函數(shù),拷貝構(gòu)造,和拷貝賦值。

從第5行起:

cout<<"------------------------\n";ConstructTest c5 ;c5=square(c4);ConstructTest c6 = std::move(c5);cout<<"------------------------\n";

首先用 默認(rèn)構(gòu)造函數(shù)創(chuàng)建對象c5,

在c5 = square(c4) 中, 首先把實(shí)參c4賦值給square的形參param,此時(shí)用的是拷貝構(gòu)造函數(shù)。

在square函數(shù)體中,創(chuàng)建了局部對象ret,此時(shí)調(diào)用構(gòu)造函數(shù),

然后為返回值ret創(chuàng)建副本,此時(shí)調(diào)用移動(dòng)構(gòu)造函數(shù),接著函數(shù)體結(jié)束,把形參param析構(gòu),

然后把原來ret的副本賦值給c5 ,對過程是對已經(jīng)存在的對象c5進(jìn)行賦值,所以調(diào)用移動(dòng)賦值。

接著把ret 和ret的副本給析構(gòu)。

利用 std::move() 手動(dòng)把c5的內(nèi)容移動(dòng)給某個(gè)臨時(shí)引用,把臨時(shí)引用初始化給c6,調(diào)用移動(dòng)構(gòu)造函數(shù).

cout<<"------------------------\n";ConstructTest c7;c7=ConstructTest();ConstructTest c8 = square(c7);ConstructTest c9 = ConstructTest();cout<<"<<<<<<finish >>>>>>>>\n";

先默認(rèn)構(gòu)造函數(shù)創(chuàng)建c7對象。

用默認(rèn)構(gòu)造函數(shù)創(chuàng)建臨時(shí)對象,把臨時(shí)對象"移動(dòng)"給c7;移動(dòng)完后把臨時(shí)對象析構(gòu)

在c8?= square(c7) 中, 首先把實(shí)參c7賦值給square的形參param,此時(shí)用的是拷貝構(gòu)造函數(shù)。

在square函數(shù)體中,創(chuàng)建了局部對象ret,此時(shí)調(diào)用構(gòu)造函數(shù),

然后為返回值ret創(chuàng)建副本,此時(shí)調(diào)用移動(dòng)構(gòu)造函數(shù),接著函數(shù)體結(jié)束,把形參param析構(gòu),

然后把原來ret的副本賦值給c8 ,對還未創(chuàng)建的對象的對象c8進(jìn)行初始化,所以調(diào)用移動(dòng)構(gòu)造

接著把ret 和ret的副本給析構(gòu)。

創(chuàng)建臨時(shí)對象,并用給c9進(jìn)行初始化,最后把臨時(shí)對象析構(gòu)掉;

程序結(jié)束,析構(gòu)所有變量。

編程思路

? ? 在類成員變量帶有指針的情況下,會(huì)面臨如何施放資源的難題。應(yīng)為默認(rèn)拷貝構(gòu)造,拷貝賦值,移動(dòng)構(gòu)造、移動(dòng)賦值只是單單的淺拷貝。即值復(fù)制 指針指向內(nèi)存的地址。在淺拷貝后,就會(huì)有兩個(gè)對象中的成員指針指向同一處內(nèi)存空間,如果在析構(gòu)函數(shù)中對成員指針delete,最后就會(huì)面臨對同一處內(nèi)存空間施放兩次。在C++中,如果訪問不屬于本程序中的內(nèi)存就會(huì)出現(xiàn)“段錯(cuò)誤”,即指針越界.?

? ? 在編程時(shí),可以利用 boost::shared_ptr 來管理動(dòng)態(tài)分配的內(nèi)存,此時(shí)可以不用理睬資源施放問題。因?yàn)橹悄苤羔樐軌驅(qū)?dòng)態(tài)內(nèi)存的引用計(jì)數(shù)歸零時(shí)自動(dòng)清理內(nèi)存空間。

? ?如果要用 普通指針來管理動(dòng)態(tài)內(nèi)存,那么就要考慮施放資源,淺拷貝與深拷貝的問題。如果想用深拷貝那么就要,寫好構(gòu)造函數(shù),拷貝構(gòu)造函數(shù),拷貝賦值運(yùn)算符,移動(dòng)構(gòu)造,移動(dòng)賦值運(yùn)算符;

? 在構(gòu)造函數(shù)中初始化所有成員變量包括指針;在拷貝構(gòu)造和拷貝賦值中重新為指針分配內(nèi)存空間,并把對應(yīng)的內(nèi)存值進(jìn)行賦值;在移動(dòng)構(gòu)造和移動(dòng)賦值中,把返回內(nèi)容復(fù)制完后要把臨時(shí)對象指針內(nèi)容重新賦空,達(dá)到不拷貝內(nèi)存又不會(huì)施放兩次內(nèi)存的目的,即所謂的"移動(dòng)“.

總結(jié)

以上是生活随笔為你收集整理的C++ : 构造函数,拷贝构造函数,移动构造函数,拷贝赋值运算符,移动赋值运算符应用场景的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。