Pointers 将托管类成员传递给c++;方法 我有一个C++ DLL,有以下方法: //C++ dll method (external) GetServerInterface(ServerInterface* ppIF /*[OUT]*/) { //The method will set ppIF } //ServerInterface is defined as: typedef void * ServerInterface;

Pointers 将托管类成员传递给c++;方法 我有一个C++ DLL,有以下方法: //C++ dll method (external) GetServerInterface(ServerInterface* ppIF /*[OUT]*/) { //The method will set ppIF } //ServerInterface is defined as: typedef void * ServerInterface;,pointers,c++-cli,Pointers,C++ Cli,为了从C#项目访问dll,我创建了一个C++/CLI项目,并声明了一个托管类,如下所示: public ref class ComWrapperManager { // // ServerInterface _serverInterface; void Connect(); // // } 我使用Connect()方法调用GetServerInterface,如下所示。第一个呼叫有效,第二个呼叫无效。有人能解释一下原因吗?我需要在托管类中将该指针作为成员变量持久化。有更好的方法吗 vo

为了从C#项目访问dll,我创建了一个C++/CLI项目,并声明了一个托管类,如下所示:

public ref class ComWrapperManager
{
//
//
ServerInterface _serverInterface;
void Connect();
//
//
}
我使用Connect()方法调用GetServerInterface,如下所示。第一个呼叫有效,第二个呼叫无效。有人能解释一下原因吗?我需要在托管类中将该指针作为成员变量持久化。有更好的方法吗

    void Connect()
    {
    ServerInterface localServerInterface;
    GetServerInterface(&localServerInterface); //THIS WORKS

    GetServerInterface(&_serverInterface); //THIS DOESNT

    //Error 1   error C2664: 'ServerInterface ' : 
    //cannot convert parameter 1 from //'cli::interior_ptr<Type>' 
    //to 'ServerInterface *'


    }
void Connect()
{
服务器接口本地服务器接口;
GetServerInterface(&localServerInterface);//这很有效
GetServerInterface(&_serverInterface);//这不是
//错误1错误C2664:“服务器接口”:
//无法从//“cli::interior\u ptr”转换参数1
//至“服务器接口*”
}

以下是无法执行第二个操作的原因:
\u serverInterface
是一个空指针,它是托管类的一部分。想想垃圾收集器做什么。。。允许在内存中随意移动托管对象,因此void指针的地址可以随时更改。因此,使用该地址是无效的

有两种解决方案:

  • 如前所述,您可以在其中将堆栈变量的地址传递给非托管方法。与托管对象不同,垃圾收集器执行其操作时堆栈不会移动,因此地址不会更改。然后,您可以获取存储在stack变量中的数据,并将其复制到class字段,这样做很好,因为您没有处理它的地址
  • 正如另一位回答者所指出的,您可以将托管对象锁定在内存中。一旦它不能移动,您就可以毫无疑问地获取void指针字段的地址。(他在展示C#syntax,你在寻找C++/CLI语法。我不是在编译器前检查,但我相信C++/CLI语法是不一样的。)

  • 在这两个解决方案中,我更喜欢第1个,即你已经实现的一个:解2,在垃圾回收器想要重新排列的空间中间引入了一个不可移动的内存块。如果有选择的话,我不想束缚垃圾收集器。

    您正在传递指向托管对象成员的指针。这种指针是特殊的,称为内部指针。它们由垃圾收集器跟踪,当GC压缩堆时移动托管对象时,垃圾收集器将修改指针值

    问题是,您正在将该指针传递给非托管代码。GC无法修改本机代码正在使用的指针值的副本。现在,当另一个线程触发垃圾收集时,灾难就会发生,而此时本机代码正在执行并取消对指针的引用。该对象在原始地址不再存在。非常非常糟糕。而且极难诊断,因为它不太可能发生

    编译器可以看到你犯了这个错误。并向C2664投诉

    解决方法是传递一个指针,该指针存储在GC不会移动的内存位置。这样的位置很容易找到,一个局部变量就可以了。它存储在堆栈上,不会被移动。所以,让它看起来像这样:

    void Connect()
    {
        ServerInterface temp;
        GetServerInterface(&temp);
        this->_serverInterface = temp;
        // etc..
    }
    

    你已经发现了,只是别忘了指定班级成员。

    谢谢Hans。答案总是很好。因此,将堆栈变量(temp)分配给类成员将使其保持固定?呃,不,关键是指向temp的指针不是内部指针,因此可以毫无困难地传递给本机代码。对类成员的赋值不会引起任何问题,因为它是在托管代码中完成的。重要的是抖动会生成代码,它会为GC创建额外的信息,让GC发现托管指针。与此引用类似,存储在CPU寄存器中。本机代码缺少该信息。我明白了。那么,在您看来,保存从GetServerInterface方法中获得的指针的最佳方法是什么?我以后在其他调用中需要它。只需将它存储在类的_serverInterface字段中,如图所示。关于这个,你有一个真正的心理障碍,我不知道如何帮助你。我第一次得到,但是你的第二个评论让我有点困惑:哦…………C++语法使用了<代码> PiNoPTR < /Cord>伪模板。