在dll接口中正确使用std :: vector(带有虚拟析构函数的类!)

我将尝试通过一个例子来解释我的问题。

我有以下课程:

__declspec(dllexport) class myclass
{
public:
    int a;
    int b;
    myclass() {};
    virtual ~myclass() {};
    // ~myclass() {};
};

myclass 用于 DLL 中,该DLL仅包含类 Test 的定义(实际上只是方法的接口) foo1 foo2 ):

class Test
{
public:
    void                 foo1   (std::vector<myclass>& val);
    std::vector<myclass> foo2   ();
};

extern "C"
{
    __declspec(dllexport) bool foo1(std::vector<myclass>& val)
    {
        val.clear();
        myclass tmp;
        val.push_back(tmp);
        val.push_back(tmp);
        val.push_back(tmp); //just an example!
        return true;
    }

    __declspec(dllexport) std::vector<myclass> foo2()
    {
        std::vector<myclass> val;
        myclass tmp;
        val.push_back(tmp);
        val.push_back(tmp);
        val.push_back(tmp); //just an example!
        return val;
    }
}

主应用程序打开DLL并调用接口方法以获得由方法 foo1 foo2 填充的向量。

typedef void                 (*FNPTR1)(std::vector<myclass>& val);
typedef std::vector<myclass> (*FNPTR2)();


int main()
{
    if (0)
    {
        HINSTANCE hInst = Loadlibrary(L"C:\\software\\mydll.dll");
        if (!hInst) { std::cout << "\nCould Not Load the library";  return EXIT_FAILURE; }
        FNPTR1 fn = (FNPTR1)GetProcAddress(hInst,"foo1");
        if (!fn) { std::cout << "\nCould not locate the function";  return EXIT_FAILURE; }

        std::vector<myclass> tmp;
        fn(tmp);
        Freelibrary(hInst);
        tmp.clear(); //crash here!
    }

    if (1)
    {
        HINSTANCE hInst = Loadlibrary(L"C:\\software\\mydll.dll");
        if (!hInst) { std::cout << "\nCould Not Load the library";  return EXIT_FAILURE; }
        FNPTR2 fn = (FNPTR2)GetProcAddress(hInst,"foo2");
        if (!fn) { std::cout << "\nCould not locate the function";  return EXIT_FAILURE; }

        std::vector<myclass> tmp;
        tmp = fn();
        Freelibrary(hInst);
        tmp.clear(); //crash here!
    }

    return 1;
}
}

不幸的是,在两种情况下(使用 foo1 foo2 ),在以下情况下,我都会收到一个“读取XXXX的访问冲突” 错误卸载dll后,我尝试在 tmp 向量上清除(或执行其他任何操作)。

仅当 myclass 的析构函数是虚拟的时,才会发生此问题。

在我的应用程序中, myclass 是自动生成的,不允许我修改析构函数定义。  但是,如果在该级别存在某种解决方案,我可以自由修改dll接口方法(即foo1 / foo2)。

我还想知道是否可以通过某种方式告诉系统将 tmp 向量用于主程序的堆,而不是.dll使用的堆。

我当前正在使用Visual Studio c ++ 2017,并且可以使用C ++ 11标准(或更高版本)

谢谢您的帮助。


回答以下评论:

  • 是的,exe和dll都是使用相同的工具链编译的。我正在使用/ MD选项。请告诉我是否应该检查其他内容。
  • 关于关于 myclass 派生的评论,我还尝试了使用基类 myclassbase myclass 的所有四种可能的组合>衍生自:

    1-具有标准析构函数的myclassbase和具有标准析构函数的myclass->确定

    2-具有标准析构函数的myclassbase和具有虚拟析构函数的myclass->崩溃

    3-具有虚拟析构函数的myclassbase和具有标准析构函数的myclass->崩溃

    4-具有虚拟析构函数的myclassbase和具有虚拟析构函数的myclass->崩溃

    因此,我可以得出结论,仅存在一个虚拟析构函数就足以产生问题。

xiacy83 回答:在dll接口中正确使用std :: vector(带有虚拟析构函数的类!)

我终于在电脑前,并且有时间仔细检查您的代码。

  1. __declspec(dllexport) class myclass错误。如果这样定义,则DLL和EXE都将期望导出变量,但是DLL必须看到一个dllexport ed类,而EXE必须看到一个dllimport ed类。
    • 要正确导出该类,您应该定义一个宏(见下文),该宏被DLL项目解释为导出,而EXE被解释为导入
    • li>
    • 必须将宏插入class关键字之后class TEST_API myclass
  2. 对于导出的功能同样有效;仅在返回函数类型TEST_API inline bool foo1(std::vector<myclass>& val)之前必须添加导出宏。
  3. 您还必须将启用导出的预处理器定义添加到DLL项目Project Properties | Configuration Properties |Preprocessor | Preprocessor DefinitionsTEST_EXPORTS
  4. 您为什么添加extern“ C”却忽略了警告? 删除
  5. 如果全局函数位于头文件中,请不要忘记添加 inline

现在应该可以使用了。

// mydll_exports.h
#pragma once

#ifdef TEST_EXPORTS
  #define TEST_API __declspec(dllexport)
#else
  #define TEST_API __declspec(dllimport)
  #pragma comment(lib,"mydll.lib")
#endif
本文链接:https://www.f2er.com/3167791.html

大家都在问