前段時間在嘗試使用一個C++的GUI庫nana。這個庫最大的特色在於使用現代C++風格去編寫GUI程序,而不須要使用大量的比較醜陋的代碼(如MFC中的各類宏),或者其它的非C++元素。這是一個比較新的庫,做者是個中國人,有興趣的朋友能夠去試一試,因爲使用大量的C++11特性,因此須要VC2013或者GCC4.7以上的編譯器。使用過程當中無心間發現了VC2013的一個重載決議(overload resolution)上的一個bug,這邊貼出來跟你們分享一下,或許能夠幫助你們少走點彎路。ios
我寫了如下簡單的代碼來重現這個問題:函數
#include <iostream> #include <string> class foo{ public: void bar(std::string = {}); }; void foo::bar(std::string str) { std::cout << str << std::endl; } int main() { foo f; f.bar(); }
編譯運行這段代碼,彈出一個錯誤:spa
按照錯誤提示,能夠找到對應的代碼1168行:指針
也就是這一行:code
_DEBUG_POINTER(_Ptr);
加個斷點能夠發現這裏面_Ptr爲空指針,因此致使程序crash。這個問題其實比較容易理解,寫一個更簡單的例子就能夠發現問題:對象
#include <string> int main() { std::string str = nullptr; }
這段代碼經過nullptr去初始化一個string,而這顯然是錯誤的。blog
但問題在於,在最初的那段代碼中,字符串
void bar(std::string = {});
這個函數聲明明明是給了函數bar一個默認參數,使其構造出一個空字符串。但爲何會調用xstring中的1168行呢?也就是參數爲一個指針的assign函數呢?get
通過屢次試驗之後發現,VC將上面這個聲明理解爲了:編譯器
void bar(std::string = {nullptr});
也就是用一個空指針去初始化一個string,從而致使了問題。一樣的代碼,在GCC4.8中是沒有任何問題的。而且若是把
void bar(std::string = {});
改成:
void bar(std::string = std::string());
在VC2013裏也沒有問題了。這也就說明了VC2013在處理{}來初始化對象時的確存在重載決議的問題。
之因此以前說這個問題比較隱蔽,是由於這種狀況只出如今類的成員函數中,若是是普通函數,就沒有這個問題:
#include <iostream> #include <string> void func(std::string = {}); int main() { func(); } void func(std::string str) { std::cout << str << std::endl; }
上面這段代碼和剛開始那段代碼幾乎同樣,惟一的不一樣在於func是一個普通函數,而bar是一個成員函數。
不知道你們有沒有遇到相似的問題?