虚拟析构函数导致访问冲突

时间:2011-05-27 14:38:21

标签: c++ destructor access-violation binary-compatibility

我正在尝试使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定义为导出/导入。

现在我在Debug模式应用程序中使用这个类,我创建一个实例并立即将其删除。

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

执行delete运算符会在mlock.c第376行给出访问冲突。

以下是callstack的副本:

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兼容时,虚函数/析构函数是否存在一般问题?

1 个答案:

答案 0 :(得分:4)

您无法导出模板定义,因为编译器会根据模板的用法生成类型。您只需在头文件或you can do something like this中内联它们,但这需要预先声明模板实例化。

另请注意,在C ++中,首选newdelete优先于mallocfree函数,尤其是如果您确实需要调用构造函数和析构函数。

修改

我会认真考虑将模板内联到任何导出尝试的方式。此外,我最初没有注意到只有当您的类是基类或包含虚方法时才需要虚拟析构函数。为什么vtable中没有任何内容?

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