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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

const constexpr C++ 解释

發布時間:2023/12/31 c/c++ 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 const constexpr C++ 解释 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

++中的const可用于修飾變量、函數,且在不同的地方有著不同的含義,現總結如下。

const的語義

C++中的const的目的是通過編譯器來保證對象的常量性,強制編譯器將所有可能違背const對象的常量性的操作都視為error。

對象的常量性可以分為兩種:物理常量性(即每個bit都不可改變)和邏輯常量性(即對象的表現保持不變)。C++中采用的是物理常量性,例如下面的例子:

1 2 3 4 5 6 7 struct?A { ????int?*ptr; }; int?k = 5, r = 6; const?A a = {&k}; a.ptr = &r; // !error *a.ptr = 7; // no error

a是const對象,則對a的任何成員進行賦值都會被視為error,但如果不改動ptr,而是改動ptr指向的對象,編譯器就不會報錯。這實際上違背了邏輯常量性,因為A的表現已經改變了!

邏輯常量性的另一個特點是,const對象中可以有某些用戶不可見的域,改變它們不會違背邏輯常量性。Effective C++中的例子是:

1 2 3 4 5 6 7 8 9 class?CTextBlock { public: ????... ????std::size_t?length() const; private: ????char?*pText; ????std::size_t?textLength;??????????? // last calculated length of textblock ????bool?lengthIsValid;??????????????? // whether length is currently valid };

CTextBlock對象每次調用length方法后,都會將當前的長度緩存到textLength成員中,而lengthIsValid對象則表示緩存的有效性。這個場景中textLength和lengthIsValid如果改變了,其實是不違背CTextBlock對象的邏輯常量性的,但因為改變了對象中的某些bit,就會被編譯器阻止。C++中為了解決此問題,增加了mutable關鍵字。

本部分總結:C++中const的語義是保證物理常量性,但通過mutable關鍵字可以支持一部分的邏輯常量性。

const修飾變量

如上節所述,用const修飾變量的語義是要求編譯器去阻止所有對該變量的賦值行為。因此,必須在const變量初始化時就提供給它初值:

1 2 3 const?int?i; i = 5; // !error const?int?j = 10; // ok

這個初值可以是編譯時即確定的值,也可以是運行期才確定的值。如果給整數類型的const變量一個編譯時初值,那么可以用這個變量作為聲明數組時的長度:

1 2 3 4 const?int?COMPILE_CONST = 10; const?int?RunTimeConst = cin.get(); int?a1[COMPLIE_CONST]; // ok in C++ and error in C int?a2[RunTimeConst]; // !error in C++

因為C++編譯器可以將數組長度中出現的編譯時常量直接替換為其字面值,相當于自動的宏替換。(gcc驗證發現,只有數組長度那里直接做了替換,而其它用COMPILE_CONST賦值的地方并沒有進行替換。)

文件域的const變量默認是文件內可見的,如果需要在b.cpp中使用a.cpp中的const變量M,需要在M的初始化處增加extern:

1 2 3 4 5 //a.cpp extern?const?int?M = 20; //b.cpp extern?const?int?M;

一般認為將變量的定義放在.h文件中會導致所有include該.h文件的.cpp文件都有此變量的定義,在鏈接時會造成沖突。但將const變量的定義放在.h文件中是可以的,編譯器會將這個變量放入每個.cpp文件的匿名namespace中,因而屬于是不同變量,不會造成鏈接沖突。(注意:但如果頭文件中的const量的初始值依賴于某個函數,而每次調用此函數的返回值不固定的話,會導致不同的編譯單元中看到的該const量的值不相等。猜測:此時將該const量作為某個類的static成員可能會解決此問題。)

const修飾指針與引用

const修飾引用時,其意義與修飾變量相同。但const在修飾指針時,規則就有些復雜了。

簡單的說,可以將指針變量的類型按變量名左邊最近的‘*’分成兩部分,右邊的部分表示指針變量自己的性質,而左邊的部分則表示它指向元素的性質:

1 2 3 4 5 6 7 8 const?int?*p1; // p1 is a non-const pointer and points to a const int int?* const?p2; // p2 is a const pointer and points to a non-const int const?int?* const?p3; // p3 is a const pointer and points to a const it const?int?*pa1[10]; // pa1 is an array and contains 10 non-const pointer point to a const int int?* const?pa2[10]; // pa2 is an array and contains 10 const pointer point to a non-const int const?int?(* p4)[10]; // p4 is a non-const pointer and points to an array contains 10 const int const?int?(*pf)(); // pf is a non-const pointer and points to a function which has no arguments and returns a const int ...

const指針的解讀規則差不多就是這些了……

指針自身為const表示不可對該指針進行賦值,而指向物為const則表示不可對其指向進行賦值。因此可以將引用看成是一個自身為const的指針,而const引用則是const Type * const指針。

指向為const的指針是不可以賦值給指向為非const的指針,const引用也不可以賦值給非const引用,但反過來就沒有問題了,這也是為了保證const語義不被破壞。

可以用const_cast來去掉某個指針或引用的const性質,或者用static_cast來為某個非const指針或引用加上const性質:

1 2 3 4 int?i; const?int?*cp = &i; int?*p = const_cast<int?*>(cp); const?int?*cp2 = static_cast<const?int?*>(p); // here the static_cast is optional

C++類中的this指針就是一個自身為const的指針,而類的const方法中的this指針則是自身和指向都為const的指針。

類中的const成員變量

?

類中的const成員變量可分為兩種:非static常量和static常量。

非static常量:

類中的非static常量必須在構造函數的初始化列表中進行初始化,因為類中的非static成員是在進入構造函數的函數體之前就要構造完成的,而const常量在構造時就必須初始化,構造后的賦值會被編譯器阻止。

1 2 3 4 5 6 7 8 class?B { public: ????B(): name("aaa") { ????????name = "bbb"; // !error ????} private: ????const?std::string name; };

static常量:

static常量是在類中直接聲明的,但要在類外進行唯一的定義和初始值,常用的方法是在對應的.cpp中包含類的static常量的定義:

1 2 3 4 5 6 7 8 // a.h class?A { ????... ????static?const?std::string name; }; // a.cpp const?std::string A::name("aaa");

一個特例是,如果static常量的類型是內置的整數類型,如char、int、size_t等,那么可以在類中直接給出初始值,且不需要在類外再進行定義了。編譯器會將這種static常量直接替換為相應的初始值,相當于宏替換。但如果在代碼中我們像正常變量那樣使用這個static常量,如取它的地址,而不是像宏一樣只使用它的值,那么我們還是需要在類外給它提供一個定義,但不需要初始值了(因為在聲明處已經有了)。

1 2 3 4 5 6 7 8 // a.h class?A { ????... ????static?const?int?SIZE = 50; }; // a.cpp const?int?A::SIZE = 50; // if use SIZE as a variable, not a macro

const修飾函數

C++中可以用const去修飾一個類的非static成員函數,其語義是保證該函數所對應的對象本身的const性。在const成員函數中,所有可能違背this指針const性(const成員函數中的this指針是一個雙const指針)的操作都會被阻止,如對其它成員變量的賦值以及調用它們的非const方法、調用對象本身的非const方法。但對一個聲明為mutable的成員變量所做的任何操作都不會被阻止。這里保證了一定的邏輯常量性。

另外,const修飾函數時還會參與到函數的重載中,即通過const對象、const指針或引用調用方法時,優先調用const方法。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class?A { public: ????int?&operator[](int?i) { ????????++cachedReadCount; ????????return?data[i]; ????} ????const?int?&operator[](int?i) const?{ ????????++size; // !error ????????--size; // !error ????????++cachedReadCount; // ok ????????return?data[i]; ????} private: ????int?size; ????mutable?cachedReadCount; ????std::vector<int> data; }; A &a = ...; const?A &ca = ...; int?i = a[0]; // call operator[] int?j = ca[0]; // call const operator[] a[0] = 2; // ok ca[0] = 2; // !error

這個例子中,如果兩個版本的operator[]有著基本相同的代碼,可以考慮在其中一個函數中去調用另一個函數來實現代碼的重用(參考Effective C++)。這里我們只能用非const版本去調用const版本。

1 2 3 int?&A::operator[](int?i) { ????return?const_cast<int?&>(static_cast<const?A &>(*this).operator[](i)); }

其中為了避免調用自身導致死循環,首先要將*this轉型為const A &,可以使用static_cast來完成。而在獲取到const operator[]的返回值后,還要手動去掉它的const,可以使用const_cast來完成。一般來說const_cast是不推薦使用的,但這里我們明確知道我們處理的對象其實是非const的,那么這里使用const_cast就是安全的。

constexpr

constexpr是C++11中新增的關鍵字,其語義是“常量表達式”,也就是在編譯期可求值的表達式。最基礎的常量表達式就是字面值或全局變量/函數的地址或sizeof等關鍵字返回的結果,而其它常量表達式都是由基礎表達式通過各種確定的運算得到的。constexpr值可用于enum、switch、數組長度等場合。

constexpr所修飾的變量一定是編譯期可求值的,所修飾的函數在其所有參數都是constexpr時,一定會返回constexpr。

1 2 3 4 5 6 7 constexpr?int?Inc(int?i) { ????return?i + 1; } constexpr?int?a = Inc(1); // ok constexpr?int?b = Inc(cin.get()); // !error constexpr?int?c = a * 2 + 1; // ok

constexpr還能用于修飾類的構造函數,即保證如果提供給該構造函數的參數都是constexpr,那么產生的對象中的所有成員都會是constexpr,該對象也就是constexpr對象了,可用于各種只能使用constexpr的場合。注意,constexpr構造函數必須有一個空的函數體,即所有成員變量的初始化都放到初始化列表中。

1 2 3 4 5 6 7 struct?A { ????constexpr?A(int?xx, int?yy): x(xx), y(yy) {} ????int?x, y; }; constexpr?A a(1, 2); enum?{SIZE_X = a.x, SIZE_Y = a.y};

constexpr的好處:

  • 是一種很強的約束,更好地保證程序的正確語義不被破壞。
  • 編譯器可以在編譯期對constexpr的代碼進行非常大的優化,比如將用到的constexpr表達式都直接替換成最終結果等。
  • 相比宏來說,沒有額外的開銷,但更安全可靠。
  • 總結

    以上是生活随笔為你收集整理的const constexpr C++ 解释的全部內容,希望文章能夠幫你解決所遇到的問題。

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

    主站蜘蛛池模板: 日本免费看 | 99热免费在线 | 黑人操日本女人 | 亚洲性色视频 | 少妇高潮伦 | 国产精品视频一区在线观看 | 久草福利资源在线 | 一区二区久久久 | 黄色在线免费观看 | 久草视 | 99久热在线精品996热是什么 | 五个女闺蜜把我玩到尿失禁 | 污色视频 | 国产情侣在线播放 | 黄视频在线播放 | jizz美女 | 欧美一区2区 | 免费看a毛片 | 亚洲视频自拍偷拍 | 国产对白在线 | 亚洲国产成人久久 | 美女网站全黄 | 调教在线观看 | 日韩伦乱 | 欧美性69| 女人下面无遮挡 | 黄色美女免费网站 | 久久片 | 亚洲乱仑| 日日干夜夜艹 | 成人精品视频一区二区三区尤物 | 尤物视频在线 | 国产精品久久久久久人妻精品动漫 | 国产午夜福利100集发布 | 国产在线97 | 91喷水视频 | 欧美成人一二三 | 男人天堂成人网 | www三级免费 | 女性裸体下面张开 | 樱桃国产成人精品视频 | 天堂在线精品视频 | 国产伦乱视频 | 国产a级黄色片 | 精品不卡视频 | 免费一级淫片 | 久草新免费 | 2019日韩中文字幕 | 丰满人妻一区二区三区四区 | 欧美性猛交xxxx偷拍洗澡 | 亚洲午夜精品久久久 | 4438x在线观看 | 视频二区在线观看 | 日韩精品视频观看 | 国产精品久久久久久久av | aaa日韩| 国产综合视频 | 亚洲综合精品视频 | 国产在线一区视频 | 免费无遮挡在线观看视频网站 | 国产成人在线观看免费网站 | 日韩看片| 夫妻啪啪呻吟x一88av | 绯色av一区 | 57pao国产成永久免费视频 | 高清视频在线免费观看 | 国产偷人妻精品一区二区在线 | 欧美高h| 国产又粗又猛又爽又黄的视频一 | 蜜臀av一区| 精品中文视频 | 久久国产精 | 欧美日日日 | 成人免费xxxxxx视频 | 玖玖网| 国产精品免费一区 | 免费看大片a | 婷婷导航| 国产亚洲精品久久久久久 | 丝袜制服影音先锋 | 亚洲大片 | 13日本xxxxxⅹxxx20 | 免费三级av | 蜜臀99久久精品久久久久小说 | 亚洲午夜精品 | 少妇一边呻吟一边说使劲视频 | 99国产成人精品 | 国产精品天美传媒沈樵 | 青娱乐在线视频观看 | 日韩永久免费 | 久久观看最新视频 | 国产一级片免费观看 | 天天色天天干天天 | 黄色激情在线 | 精品国产乱码久久久久久1区2区 | 日韩精品偷拍 | 美日韩精品| 天天艹日日艹 | 欧美精品久久久久久久久老牛影院 |