您好,登錄后才能下訂單哦!
這篇文章主要講解了“關于C++的坑有哪些”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“關于C++的坑有哪些”吧!
1. string的字符串拼接,導致coredump
該問題的核心點在于第9行,竟然是可以編譯通過,其原因是x+"-",會被轉成char*,然后與to_string疊加導致BUG。
2. map的迭代器刪除
map要刪除一個元素,通常通過erase()函數來完成,但是要注意,如果我們傳入了一個iterator作為erase的參數來刪除當前迭代器所指向的元素,刪除完成后iterator會失效,產生未定義行為。
正確的使用方法應該是接收erase()的返回值,讓iterator指向被刪除元素的下一個元素或者end()。
for ( auto iter = m.begin(); iter != m.end(); iter++) { if (...) iter = m.erase(iter); }
但是上述代碼仍然有錯誤,因為如果觸發了刪除,那么iter再下一輪循環時會指向下下個元素,所以正確的寫法應該是:
for ( auto iter = m.begin(); iter != m.end();) { if (...) { iter = m.erase(iter); continue ; } else { iter++; } }
3. stringstream的性能問題
鴻蒙官方戰略合作共建——HarmonyOS技術社區
stringstream的清空是clear之后,置空。
stringstream在任何情況下都比snprintf慢。
memset是個很慢的函數,寧愿新創建對象。
上述測試結果是單線程,改成多線程,同樣成立。
str += “a”, 比 str =str+ “a” 效率高很多,后者會創建新對象。
4. 智能指針(shared_ptr)使用注意
4.1盡量使用make_shared初始化
提高性能
std::shared_ptr<Widget> spw(newWidget);
需要分配兩次內存。每個std::shared_ptr都指向一個控制塊,控制塊包含被指向對象的引用計數以及其他東西。這個控制塊的內存是在std::shared_ptr的構造函數中分配的。因此直接使用new,需要一塊內存分配給Widget,還要一塊內存分配給控制塊
autospw = std::make_shared<Widget>();
一次分配就足夠了。這是因為std::make_shared申請一個單獨的內存塊來同時存放Widget對象和控制塊。這個優化減少了程序的靜態大小,因為代碼只包含一次內存分配的調用,并且這會加快代碼的執行速度,因為內存只分配了一次。另外,使用std::make_shared消除了一些控制塊需要記錄的信息,這樣潛在地減少了程序的總內存占用。
異常安全
processWidget(std::shared_ptr<Widget>( new Widget), //潛在的資源泄露 computePriority());
上述代碼存在內存泄漏的風險,上述代碼執行分為3個步驟:
1. new Widget
2. shared_ptr構造
3. computePriority
編譯器不需要必須產生這樣順序的代碼,但“new Widget”必須在std::shared_ptr的構造函數被調用前執行。如果編譯器產生的順序代碼如下:
1. new Widget
2. 執行computePriority。
3. 執行std::shared_ptr的構造函數。
如果執行步驟2:computePriority的時候程序出現異常,則在第一步動態分配的Widget就會泄露了,因為它永遠不會被存放到在第三步才開始管理它的shared_ptr中
4.2 父類之類智能指針轉換
C++中是允許裸指針,因此裸指針之間轉換方法同C語言指針強轉,智能指針轉換不能通過上述方法進行強轉,必須通過庫提供轉換函數進行轉換。C++11的方法是:std::dynamic_pointer_cast;boost中的方法是:boost::dynamic_pointer_cast
#include <memory> #include <boost/shared_ptr.hpp> #include <boost/make_shared.hpp> #include <iostream> class Base { public : Base(){} virtual ~Base() {} }; class D : public Base { public : D(){} virtual ~D() {} }; int main() {
//方式一:先初始化子類智能指針,然后調用dynamic_pointer_cast轉換成基類智能指針對象
std::shared_ptr<D> d1 = std::make_shared<D>(); std::shared_ptr<Base> b1 = std::dynamic_pointer_cast<Base>(d1);
//方式二:先new子類D的指針,然后調用shared_ptr的構造函數初始化基類智能指針
std::shared_ptr<Base> b2 = shared_ptr<Base>( new D()); return 0; }
結論
方式一和方式二均能夠實現基類智能指針指向子類,但建議采用方式1,通過std::make_shared的方式構造智能指針,然后進行轉換;
5. map的安全查找辦法
即map[key]這種寫法,就是會創建元素(且不一定初始化),因此在業務邏輯是希望查找的時候,就老老實實用find,不然會有臟數據寫入。
6. string 的指針構造
std::string 的構造方式,除了與其它順序容器相近的方式之外,提供了三種額外的構造方式:
string s(cp, n): s 是cp指向的數組中前n個字符的拷貝,該數組至少應該包含n個字符
string s(s2, pos2):s 是string s2從下標pos2開始的字符的拷貝,若pos2>s2.size(),構造函數的行為未定義
string s(s2, pos2, len2):s 是string s2從下標pos2開始len2個字符的拷貝,若pos2>s2.size(),構造函數的行為未定義。不管len2的值是多少,構造函數至多拷貝s2.size()-pos2個字符
std::string 未提供 string(cp, pos2, len2) 這種構造方式,如果代碼中使用了該方式,最終會將 cp 指向的數組構造成一個string,然后調用string(s2, pos2, len2)這種構造方式。
不提供string(cp, pos2, len2)這種構造方式原因在于:使用這種方式構造容易出現問題,cp是一個指針,通常使用時,能獲得其數組長度并檢查傳入參數;若傳入兩個參數,容易出現越界。
7. 變量初始化
變量初始化總是沒錯的,不管后面是否會修改該值。尤其是int等內建的類型,在類或struct中及容易忽略初始化,使變量成為隨機值,產生不可預知的錯誤。變量請初始化!變量請初始化!!變量請初始化!!!
感謝各位的閱讀,以上就是“關于C++的坑有哪些”的內容了,經過本文的學習后,相信大家對關于C++的坑有哪些這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。