3

我正在尝试使 DLL 文件与不同的编译器配置(调试、发布、..)兼容。为了确保以正确的方式删除对象,我设法编写了一个指针包装类,该类在我获取 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;

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

4

1 回答 1

4

您无法导出模板定义,因为编译器会根据模板的使用情况生成类型。您只需将它们内联在头文件中,或者您可以执行类似的操作,但这需要预先声明您的模板实例化。

还要注意 C++ 中的偏好new和Cdelete中的malloc函数free,特别是如果您确实希望调用构造函数和析构函数。

编辑:

我会认真考虑模板的内联优于任何导出尝试。此外,我最初没有注意到只有当您的类是基类或包含虚拟方法时才需要虚拟析构函数。为什么有一个没有任何内容的 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++ 标准最终确定时,导出模板支持将从新 C++ 标准中完全删除(不弃用,删除)。头文件中的内联模板将是编译器将在不久的将来实现并允许的唯一解决方案,因此现在要习惯以这种方式编写它们。请参阅Herb Sutter 关于 C++0x 的问答

于 2011-05-27T15:22:37.290 回答