VC2013的一個bug

前段時間在嘗試使用一個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

image

按照錯誤提示,能夠找到對應的代碼1168行:指針

image

也就是這一行: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是一個成員函數。

不知道你們有沒有遇到相似的問題?

相關文章
相關標籤/搜索