2011-05-27 31 views
3

我正在嘗試使DLL文件與不同的編譯器配置(Debug,Release,..)兼容。爲了確保以正確的方式刪除對象,我設法編寫了一個指針包裝類,該指針包裝類使用編譯的刪除操作符,只要我獲取DLL的對象並超出範圍即可。虛擬析構函數導致訪問衝突

我對此很滿意,但是當我嘗試刪除我在同一個方法/程序中分配的內存時,我的程序崩潰。

以下是在一個標準的發佈模式編譯一些示例代碼:

template <typename T> 
class API mwCompatibleObject 
{ 
public: 

    //! Constructor 
    mwCompatibleObject(); 

    //! Destructor 
    virtual ~mwCompatibleObject(); 
}; 

源代碼

template < typename T > 
mwCompatibleObject<T>::mwCompatibleObject() {} 

template <typename T> 
mwCompatibleObject<T>::~mwCompatibleObject() {} 

注:API被定義爲出口/進口。

現在我在調試模式應用程序中使用這個非常類的應用程序,我創建一個實例並立即刪除它。

mwCompatibleObject<double> * obj = new mwCompatibleObject<double>(); 
delete obj; 

執行delete操作符提供了一個訪問衝突在mlock.c線376

這裏是調用堆棧的副本:

ntdll.dll!7721e3be()  
[Frames below may be incorrect and/or missing, no symbols loaded for ntdll.dll] 
msvcr80d.dll!_unlock(int locknum=4) Line 376 C 
msvcr80d.dll!_heap_alloc_dbg(unsigned int nSize=0, int nBlockUse=2968120, const char * szFileName=0x2e2ed26c, int nLine=1638180) Line 477 + 0x7 bytes C++ 
msvcr80d.dll!_heap_alloc_dbg(unsigned int nSize=0, int nBlockUse=2968120, const char * szFileName=0x2e2ed26c, int nLine=1638180) Line 474 + 0xc bytes C++ 
00300000() 
msvcr80d.dll!malloc(unsigned int nSize=2968120) Line 154 + 0x15 bytes C++ 
5axutil.dll!100b5d09() 
Integrator3.exe!main() Line 54 + 0x34 bytes C++ 

我不能跳進該行或除了我設法看看彙編代碼,這證明了我的觀察,它與析構函數有關。

嘗試使DLL兼容時,是否存在虛擬函數/析構函數的一般問題?

+0

導出/導入對模板沒有意義。包含頭文件時,調用應用程序中定義了'mwCompatibleObject'。 – Blazes 2011-05-27 14:46:09

+0

您是否在使用您的dll的目標項目中構建源代碼?您可以嘗試將頭文件中的模板化實現(您的源文件)放在類的聲明之上。 – vrince 2011-05-27 14:46:48

+0

如果你只編譯你發佈的代碼,它是否仍然崩潰?我敢打賭問題是你的程序中的其他地方存在堆腐敗問題。 – bk1e 2011-05-27 14:48:13

回答

4

由於編譯器根據模板的使用生成類型,因此無法導出模板定義。您只需將它們內聯到頭文件或you can do something like this,但需要預先聲明您的模板實例化。

還要注意在C++更喜歡由C newdelete超過mallocfree功能,特別是如果你真的想構造函數和析構函數被調用。

編輯:

我會認真考慮的模板內聯最好的任何企圖出口。此外,我最初並未注意到,只有當您的類將是基類或包含虛擬方法時才需要虛擬析構函數。爲什麼有一個沒有任何內容的虛擬桌面?

template <typename T> 
class mwCompatibleObject // no need for export if inlined in header 
{ 
public: 
    //! Constructor 
    mwCompatibleObject() {} 
    //! Destructor (don't need virtual unless it's a base class or has virtual methods) 
    ~mwCompatibleObject() {} 

    //! Some public method 
    void DoSomething(const T& withSomething) 
    { 
     // ... yata yata 
    } 
private: 
    T m_member; 
}; 

進一步編輯:

我剛剛發現導出模板支撐將被全部刪除時,在最終確定由新的C++標準(不會被棄用,刪除)。頭文件中的內聯模板將是編譯器將在不久的將來實現和允許的唯一解決方案,所以現在就習慣以這種方式編寫它們。請參閱Herb Sutter's Questions & Answers about C++0x

+0

謝謝大家的回答。 我忘了發佈源文件中的顯式實例化代碼。它可以使用float和double類型的模板,所以不用擔心導出/導入,它肯定會被使用。 我想補充一點,這段代碼是完全獨立的。我沒有添加任何其他內容,並試圖通過在崩潰時僅使用必要的代碼來縮小問題範圍。 今天我試了一些其他案例,並發現,在某些情況下,它可能會在API僅在導出時定義時崩潰。這有可能是我的錯誤來源嗎? – 2011-06-09 07:12:13

+0

你最終在那裏失去了我......如果你仍然有問題,我只是將模板內聯。看到我上面的編輯。 – AJG85 2011-06-09 15:26:07

+0

+1 yata yata !!!! тра-та-та! – 2011-06-09 15:34:41