第十二篇:SOUI的utilities模塊為什么要用DLL編譯?


SOUI相對於DuiEngine一個重要的變化就是很多模塊變成了一個單獨的DLL。

然后很多情況下用戶可能希望整個產品就是一個EXE,原來DuiEngine提供了LIB編譯模式,此時鏈接LIB模式的DuiEngine就行了。

但是SOUI默認至少Utilities那個模塊是不提供LIB編譯模式的。

utilities之所以默認只提供DLL編譯是因為SString類是由utilities實現的。

字符串是編譯中碰到的最最見的基本對象之一。在運行庫(CRT)動態編譯(MD,MDd)時這不是問題,因為所有模塊的內存分配都是在一個相同的運行庫(CRT)上,這時在不同模塊之間傳遞對象相對簡單。如果項目采用運行庫靜態編譯(MT or MTd),在不同模塊之間傳遞字符串對象是非常困難的,因為一不小心就會發生在A模塊中分配的字符串對象被B模塊釋放。

utilities采用DLL編譯就是為了解決這個字符串對象的跨模塊傳遞。

采用運行庫動態編譯的情況就不說了,這里主要介紹采用靜態庫編譯的CRT的情況。

SOUI中使用的字符串對象采用了一點技巧:每一個String對象中只有一個指針成員變量:

    template <class tchar, class tchar_traits>
    class TStringT
    {
    public:
        typedef tchar    _tchar;
        typedef const _tchar * pctstr;

    protected:
        tchar* m_pszData;   // pointer to ref counted string data
    };

雖然TStringT是一個模板類,在SOUI中采用類導出的方式將該模板的兩個特化類導出:

#ifdef UTILITIES_EXPORTS
#    define EXPIMP_TEMPLATE
#else
#    define EXPIMP_TEMPLATE extern
#endif

     #pragma warning (disable : 4231)

    EXPIMP_TEMPLATE template class UTILITIES_API  TStringT<char, char_traits>;
    EXPIMP_TEMPLATE template class UTILITIES_API  TStringT<wchar_t, wchar_traits>;

通過將string類導出,保證string的所有運行代碼都是在utilities這個模塊內部,這也就保證了string對象的唯一成員變量:

tchar* m_pszData;

的內存分配及釋放固定在utilities這個模塊里。

通過這樣處理,無論用戶定義string是在哪一個模塊,真正的內存管理還是在utilities里,從而使得string對象可以方便的在不同模塊之間傳遞。

比較一下std::string就可以發現,如果使用std::string在不同模塊之間傳遞對象將是非常危險的,因為std::string是模板類,它的代碼將會被編譯到不同的模塊中,也就是說在不同的模塊中調用std::string的成員函數執行的代碼是不一樣的,這樣在A模塊中聲明的string傳遞到B模塊再被B模塊釋放程序就崩潰了。

這就是為什么utilities模塊默認只提供DLL編譯的原因。

知道了原因就好辦了。

對於那些希望整個項目就是一個EXE的情況,直接修改utilities模塊的編譯類型為LIB就行了,因為這種情況下根本不存在跨模塊對象傳遞的問題。




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM