這是使用 C++11 codecvt
時遇到的一個坑,轉換編碼時,mbstate_t
這個中間狀態變量,必須初始化爲0,不然運行出錯,即:promise
// 不能夠! mbstate_t mbst; // 這樣能夠 mbstate mbst = {0}; // 這樣也行 mbstate mbst = mbstate_t();
這是第一個坑,並不算太坑,還比較容易調試和發現,也怪本身大意了。安全
經驗:C++中的變量必定要初始化後再使用。 app
這個坑要和 boost 進行比較,在 boost 中,是能夠建立匿名 thread 對象的,而且這樣的匿名對象跟 future、promise是能夠正常配合使用的(《Boost標準庫徹底開發指南》一書中的示例代碼就是這樣寫的)。函數
可是,在 C++ 標準庫中不能這麼幹,會出現莫名其妙的錯誤,調試時也不會顯示任何有價值的信息,最終肯定這個問題真是費了我好大勁,由於根本沒想到會是這個問題,畢竟 boost 裏都正常使用了。編碼
經驗:儘可能不使用匿名對象,若是想要用完當即釋放,可使用單獨的代碼塊包裹。 線程
這是一個坑了我一天的大坑。指針
C++11 中,新引入了 thread_local
存儲類型,等同於以前的 __declspec(thread)
,因爲其具備真正的可移植性,因此我就嘗試使用了,但這也是噩夢的開始。調試
我有一段代碼,若是編譯爲 exe,在 xp 系統上能正常運行,但若是編譯爲 dll,在 xp 上運行就出錯。因爲 xp 上不能安裝 VS 這種高科技玩意,只能用 x32_dbg 湊合調試,發現是空指針異常,指針來源爲 fs:[2c],這是 TLS 指針啊,而後百度,找到了微軟的文檔 https://msdn.microsoft.com/en... :code
On XP systems, thread_local may not function correctly if a DLL uses thread_local data and it is loaded dynamically via LoadLibrary.
是的,若是 dll 中使用了 thread_local
,這個 dll 將不能在 xp 上經過 LoadLibrary
動態加載。對象
解決辦法也是有的:
LoadLibrary
動態加載,那我靜態加載不就好了,只要在編譯 exe 時靜態連接 dll,即 dll 在 exe 的導入表中,那就能夠正常運行(這也要求 exe 必須是本身可編譯的)DllMain
中使用 TLS 相關的 API 手動初始化經驗:或許我應該拋棄 xp 了。
這個坑跟上個坑是同時出現的,只是我當時用了靜態連接的方式後,就運行正常了,也就沒在乎。直到後來又想在 C# 中調用 dll,這回沒辦法靜態連接了。爲了先實現功能,我選擇了暫時刪除 thread_local
,可是在 xp 上依然運行出錯,錯誤緣由跟以前同樣!臥槽,我特麼明明都刪掉了 thread_local
呀,爲什麼還這樣!!
又通過2個小時的調試,最終肯定問題出在 C++17 標準庫中的 std::experimental::filesystem::exists()
函數,可是通過我單步調試發現,這個函數並無使用 TLS,只用到了一些全局靜態對象,莫非是全局靜態對象的問題?
因而仍是找文檔吧,跟上個問題同一個網址 https://msdn.microsoft.com/en... :
Starting in C++11, a static local variable initialization is guaranteed to be thread-safe. This feature is sometimes called magic statics. However, in a multithreaded application all subsequent assignments must be synchronized. The thread-safe statics feature can be disabled by using the /Zc:threadSafeInit- flag to avoid taking a dependency on the CRT.
在 C++11 中,靜態變量的初始化是線程安全的,這個所謂的「線程安全」,就是引入了 TLS 來進行一些額外的檢查,好在這個特性是能夠禁用的,編譯時添加 /Zc:threadSafeInit-
選項便可(注意最後的減號),禁用後就不會使用 TLS 了,也就能夠在 xp 上動態加載了。
經驗:xp 去死吧!去死吧!去死吧!
注:這些問題在 VS2015 Update 2 中發現,應該也會持續存在於以後的 VS 版本中。