C++坑點集合 - 1 隱式調用和默認實現的構造函數的坑


C++是一個編譯器會替你在背后做很多事情的語言,包括模板實例化,按需要創造隱式的構造函數,默認構造你沒有顯式構造的成員,按需進行隱式轉換和飲食構造等等,如果沒有徹底了解清楚,就容易被這些編譯器背后做好的事情坑到,這個系列文章就來總結我在寫C++時遇到的各種坑。

 

所謂隱式調用和默認實現的構造函數,當你寫一個賦值語句的時候,編譯器會首先檢查兩個類型又沒有直接實現的賦值函數,然后檢查賦值左右的類型是否能做隱式轉換和構造,轉換或者構造好之后,再嘗試進行拷貝或移動賦值。這時候,坑點來了,如果你有這么樣的一個類:

struct Token
{
    int label;
    string content;
    Token(int _label = -1, string _content = "")
        : label(_label)
        , content(_content)
    {}
};

看它的構造函數,每一個參數都有默認參數,這個東西是會被編譯器當成默認構造函數的,並且這個構造函數不會被視為用戶自己實現的構造函數,所以編譯器依然會按需自動生成其他的[拷貝|移動][構造|賦值]函數,所以這時候坑點來了,以下的語句是合法的:

Token label(1, "hello");

label = 2; //這tm是合法的!!!

label = 2,這條語句會讓編譯器隱式調用Token的構造函數用2構造一個Token,參數的_content采用默認值“”,然后又調用隱式生成的移動賦值(move assignment)函數,進行賦值。而且毫無警告發生,這樣寫可能還比較明顯,容易發現問題,如果代碼復雜起來,被坑的可能性就大大提高了,我自己的tokenizer generator就是有一個bug坑在了這個地方,幸虧IDE能識別出運算符重載以及顯示鼠標指向的變量的值,讓我很快發現了這個bug,不然又不知道要debug到猴年馬月去了。這個問題還說明了使用一個牛逼的IDE的重要性,倘若是用VC6……呵呵呵呵呵。

話說我該把這個構造函數聲明為explicit的,忘了


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM