中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C++中const與constexpr的區別是什么

發布時間:2021-11-29 10:47:18 來源:億速云 閱讀:197 作者:iii 欄目:開發技術

這篇文章主要講解了“C++中const與constexpr的區別是什么”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“C++中const與constexpr的區別是什么”吧!

    一.const常量與#define比較

    define只是簡單的替換,沒有類型,const可以做到防竄改與類型安全。

    而且#define會在內存中可能(有幾次替換就有幾次拷貝)有多份拷貝,對于字面值常量加不加const都一樣,例如:const char* arr = “123”;,儲存在常量區,只有一份拷貝;對于局部對象,常量存放在棧區,例如:void add(){const char crr[] = “123”;},這里“123”本應儲存在棧上,但編譯器可能會做某些優化,將其放入常量區;對于全局對象,常量存放在全局/靜態存儲區;用const會比#define使用更少的空間,效率更高。

    這里有一個小例子:char* brr = "123"; char drr[] = "123";前者字符串123存在常量區,不能通過brr去修改"123"的值;后者"123"保存在棧區,可以通過drr去修改。

    現在C++除了一些特定用法,推薦用const,inline,enum等替換宏——來自《Effective C++》條款02

    二.const修飾

    1.修飾普通變量,必須初始化

    const int a = 10; 表示int對象a,是一個常量,不可以改變值,從編譯器生成二進制角度看,生成的a存放在.rodata段,也就是只讀(readonly)區域。不過并不絕對,有的時間統計優化等級開的高,也不取地址,可能會優化成立即數在.text段中。

    2.修飾類變量和成員變量

    class cAAA{
    public:
        cAAA(int a) : m_iV(a){}
        const int GetValue() const {return m_iV;}
        void AddValueOneTime(){m_iChangeV++;}
    private:
        const int m_iV;
    public:
        mutable int m_iChangeV;
        static const int m_iStaticV;
    };
    static const int m_iStaticV = 1000;
    
    const cAAA aa(100);
    aa.GetValue();
    aa.m_iChangeV++;
    • cAAA類成員m_iV是const變量,必須放到初始化列表中進行初始化,不能進行賦值。

    • 對于靜態常成員,與普通靜態成員類似,推薦放到類外.cpp中初始化。

    • aa只能調用const函數,如aa.GetValue(),不能調用非常成員函數aa.AddValueOneTime()。

    • 對于這種const對象,又想修改成員,可以在成員聲明加上mutable,這樣const對象aa也可以修改m_iChangeV,這種用法比較少。

    3.修飾成員函數

    • 表示這個函數可以被const對象調用,也可以被普通對象調用,不會改變對象的成員,也就是說更像一種只讀不寫型的邏輯運算,所以有些人推薦類成員函數,可以都加上const。有一個小技巧,當const和non-const成員函數有著實質等價的實現時,令non-const版本調用const版本可避免代碼重復;但反過來不行,const函數內部也必須只能調用const函數—— 《Effective C++》條款03

    • 有一點要注意,編譯器強制實施bitwase constness,但編寫程序時應該使用conceptual constness,解決編譯器的bitwase constness屬性就用到了上述的mutable。關于介紹bitwase constness的具體表現可以參考《Effective C++》條款03。

    4.修飾指針

    const char* p1;
    char const *p2;
    char* const p3;
    const char* const p4;

    對于初學者來說這大概是很難理解的一個知識點,怎么區分這四個呢?記住秘訣,直接從右向左讀就一招制敵了。

    • p1是一個指針,指向char字符常量,表示p1所指對象內容不可以改,所指地址可以改。

    • p2同p1,寫法不同,兩者等價。

    • p3是一個常量,且是個指針,指向char字符,表示p3所指對象內容可以改,所指地址不可以改。

    • p4是一個常量,且是個指針,指向char字符常量,表示p4所指對象內容不可以改,且所指地址也不可以改。

    • 相對來說p1,p2是最常用傳參或者返回值的手段。

    5.修飾引用

    修飾引用和對象差不多,對象內容不可以改變。作為函數參數傳參數,不存在copy開銷,這是比較推薦的寫法,例如:拷貝構造函數,賦值構造,STL里用于比較的函數或者仿函數,詳情請參閱《Effective C++》條款20。bool Less(const cAAA& left, const cAAA& right);

    float dValue = 1.05f;
    const int& a = dValue;
    
    const int iTemp = dValue;
    const int& a = iTemp;

    因為常引用不能改變,這種情況下編譯器會創建一個臨時變量來處理隱式轉換,我們實際是對臨時變量進行了常引用。

    三.const轉換

    一般來說,從T*轉換到const T*是比較簡單的,且編譯器支持的隱式轉換,也可以顯示的用模板處理,例如我們簡單寫一下RemoveConst模板,最后用using化名一下。但從const T*T*就麻煩一些,推薦使用const_cast。

    template <typename T>
    struct RemoveConst{
        typedef T Type;
    };
    
    template <typename T>
    struct RemoveConst<const T>{
        typedef T Type;
    };
    
    template <typename T>
    using RCType = typename RemoveConst<T>::Type;

    四.頂層const與底層const

    • 簡單來說const修飾的對象本身不能改變就是頂層const,但如果是指針或者引用的對象不能改變,則稱為底層const。

    • const int cV = 10; cV是頂層const,本身不能改變

    • char const *p2; p2是底層const,p2本身值可以改變,但所指內容不可以改變

    • char* const p3; p3是頂層const,p3的本身值不可以改變

    • const char* const p4; p4既是頂層const,又是底層const

    • 注:對于上述模板RCType是無法移除p2這種底層const,如果要移除,請用const_cast<T*>移除,但這種操作可能引起Crash或者未知風險

    const char* pA = "sss";
    char* pB = const_cast<char*>(pA);
    auto pC = RCType<decltype(pA)>(pA);
    std::cout << "type is the same: " << std::is_same<decltype(pB), decltype(pC)>::value << std::endl;
    std::cout << "pB Type Name: " << typeid(pB).name() << "pc Type Name: " << typeid(pC).name() << std::endl;
    //pB[0] = 'A';//error, Segmentation fault

    五.C++11新引入的constexpr

    這個關鍵字表示這是一個常量表達式,是一個編譯期就可以確認的值,最常用于模板中,例如模板遞歸求值。

    它可不只是變量,例如:

    const int iSize1 = sizeof(int);
    const int iSize2 = GetSize();

    iSize1是個常量,編譯期的,但iSize2就不一定,它雖然不能改變,但要到GetSize()執行結束,才能知道具體值,這與常量一般在編譯期就知道的思想不符,解決這個問題的方法就是改為:constexpr int iSize2 = GetSize(); 這樣要求GetSize()一定要能在編譯期就算出值,下面幾個例子中GetSizeError()就會編譯失敗。GetFibo函數,編譯期就已經遞歸計算出值。

    constexpr int GetSize(){
      return sizeof(int) + sizeof(double);
    }
    
    constexpr int GetSizeError(){
      return random();
    }
    
    constexpr int GetCalc(int N){
      return N <= 1 ? 1 : N * GetCalc(N - 1);
    }
    
    const int iSize1 = sizeof(int);
    constexpr int iSize2 = GetSize();
    //constexpr int iSize3() = GetSizeError();
    constexpr int iSize4 = GetCalc(10);
    std::cout << iSize1 << " " << iSize2 << " " << iSize4 <<std::endl;

    當然我們可以用模板寫GetCalc函數:

    template <int N>
    struct TCalc{
      static constexpr int iValue = N * TCalc<N-1>::iValue;
    };
    
    template <>
    struct TCalc<1>{
      static constexpr int iValue = 1;
    };
    std::cout << TCalc<10>::iValue << std::endl;

    感謝各位的閱讀,以上就是“C++中const與constexpr的區別是什么”的內容了,經過本文的學習后,相信大家對C++中const與constexpr的區別是什么這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    北票市| 黄大仙区| 辽阳县| 全椒县| 杂多县| 维西| 唐海县| 麦盖提县| 长顺县| 钟祥市| 绥芬河市| 静宁县| 福鼎市| 承德县| 思南县| 科技| 伊金霍洛旗| 西和县| 衡水市| 凭祥市| 开阳县| 丹巴县| 高要市| 信宜市| 永修县| 福鼎市| 遂川县| 临江市| 温泉县| 富平县| 原阳县| 辽宁省| 中西区| 龙门县| 南城县| 东乡| 文昌市| 宁阳县| 七台河市| 越西县| 呼和浩特市|