計(jì)算機(jī)二級(jí):vc++6.0標(biāo)準(zhǔn)庫string類的bug

字號(hào):

basic_string類的用途
    basic_string并不象它的名字那樣,只可能是一個(gè)字符串。有時(shí)候,它不那么象字符串。例如:
    typedef std::basic_string DoubleArray;
    此時(shí),basic_string是一個(gè)double類型的動(dòng)態(tài)數(shù)組。你可能說,為什么不用vector呢?如下:
    typedef std::vector DoubleArray;
    這兩者有什么不同?其實(shí)的不同,在于basic_string類通常是基于copy-on-write技術(shù)的。這意味著basic_string的賦值操作(operator=)只是一個(gè)簡單的加引用計(jì)數(shù)(AddRef),是相當(dāng)快速的。而vector類的賦值操作則是真正的內(nèi)存拷貝過程。
    現(xiàn)在我要實(shí)現(xiàn)一個(gè)矩陣(Matrix)類。你可以想象一下現(xiàn)在要矩陣的各種運(yùn)算,例如加法(operator+):
    Matrix operator+(const Matrix& a, const Matrix& b)
    {
    Matrix result = a;
    result += b;
    return result;
    }
    你可以發(fā)現(xiàn),如果Matrix內(nèi)部采用vector,而不是用basic_string,那么Matrix類的operator+中就有多次無謂的內(nèi)存拷貝過程。
    bug的發(fā)現(xiàn)
    我的Matrix類一直工作的很好,直到有一天,我發(fā)現(xiàn)某個(gè)Matrix的數(shù)據(jù)少了。跟蹤發(fā)現(xiàn),問題出在basic_string的copy-on-write實(shí)現(xiàn)上。vc++ 6.0的stl中,basic_string通過_Split函數(shù)進(jìn)行分裂:
    class basic_string {
    void _Split()
    {if (_Ptr != 0 && _Refcnt(_Ptr) != 0 && _Refcnt(_Ptr) != _FROZEN)
    {_E *_Temp = _Ptr;
    _Tidy(true);
    assign(_Temp); }}
    };
    問題出在上面的assign語句上。你的數(shù)組被理解為是一個(gè)''結(jié)尾的“字符串”。這樣_Split操作完成后,如果某個(gè)數(shù)組元素為0,數(shù)據(jù)變少了。
    bug的修復(fù)
    找到了肇事者,修改代碼還是很容易,如下:
    void _Split()
    {if (_Ptr != 0 && _Refcnt(_Ptr) != 0 && _Refcnt(_Ptr) != _FROZEN)
    {_E *_Temp = _Ptr;
    size_type _N = _Len;
    _Tidy(true);
    assign(_Temp, _N); }} //@@code modify: assign(_Temp); ---> bug fixed by xushiwei
    問題在于:
    既然它是標(biāo)準(zhǔn)庫,直接修改它的代碼并不是很好,因?yàn)槟愕耐拢ɑ蛘咂渌耍┻€在用著有問題的版本。
    如果你采用MultiThread DLL模式鏈接C++標(biāo)準(zhǔn)庫,這意味著就算你修改了vc++的頭文件也沒用,因?yàn)榫幾g器最終鏈接的是dll中的代碼,而不是你修改后的代碼。
    怎么辦呢?
    winx就這個(gè)問題進(jìn)行了一定程度的修復(fù)(參見最新的發(fā)布包)。也就是說,只要你包含了最新的winx,多數(shù)情況下不會(huì)出現(xiàn)此bug。但如果你采用MultiThread DLL模式鏈接C++標(biāo)準(zhǔn)庫(問題挺嚴(yán)重,因?yàn)檫@是推薦的鏈接方式),那么你需要小心使用string、wstring類(但是其他類諸如basic_string沒問題),因?yàn)榇四J较聎inx并沒有修復(fù)該bug。注意不要讓字符串中出現(xiàn)''字符即可。如果確實(shí)需要出現(xiàn)''的字符串,可使用winx::CString類。