C ++ / CLI指针问题=好玩!

时间:2010-10-07 23:19:58

标签: pointers c++-cli c#-2.0

我一直在将一堆旧的C ++代码转换为C ++ / CLI代码,我想我已经将自己编写成了一个角落。

我的目标是获取一个非托管的c ++库和一堆头文件,并将其功能公开给C#解决方案。从在互联网上阅读,标准的方法是:

  • 创建两个c ++类:一个是托管的,另一个是非托管的。
  • 非托管类将对c ++库中的对象进行争论,以提供所需的功能。
  • 托管类将包装非托管类中的所有公共方法。每个包装器方法将处理从String ^到string等的必要转换。

但是,我的场景并不复杂,所以我决定尝试在一个类中实现所有内容。我现在正在努力解决生成AccessViolationExceptions的特殊问题。

我的头文件如下所示:

public ref class ManagedClass
{
public:
  ManagedClass();
  void CreateUnmanagedObject(String^ param1);
  void UseUnmanagedObject();

  UnmanagedObject *myUnmanagedObject;
}

我的cpp文件如下所示:

void ManagedClass::CreateUnmanagedObject(String^ param1)
{
   /* Convert params, use them in some way. */

   /* capture the output of this library call to the pointer defined in ManagedClass.*/
   myUnmanagedObject= &(LibrayObject.LibraryMethod1());  
}
void ManagedClass::UseUnManagedObject()
{
   /* This function will pass the Unmanaged object into
    * a library function which will do some work on it.
    */
   LibraryObject.LibraryMethod2(*myUnmanagedObject);
   /* Whoops! System.AccessViolationException is thrown! */
}

有趣的是,如果我在LibraryMethod1之后立即在CreateUnmanagedObject中调用LibraryMethod2,它可以正常工作。但是在CreateUnmanagedObject退出之后,似乎myUnmanagedObject指向的内存丢失了。

任何人都可以看到发生这种情况的原因吗?

编辑:库声明如下所示:

UnmanagedObject LibraryMethod1();
void LibraryMethod2(UnmanagedObject &param);

3 个答案:

答案 0 :(得分:1)

您是否没有获取临时变量的地址?如果

LibraryObject.LibraryMethod1()

返回某个值的副本,然后您将获取局部变量的地址,该变量超出了方法末尾的范围。之后使用该地址是未定义的行为,在这种情况下会导致访问冲突!

答案 1 :(得分:1)

不确定你的真正问题是什么,但看起来都错了。托管包装器应该是非托管包装的非常接近的传真。让我们从像这样的非托管声明开始工作:

class Unmanagedclass {
public:
    Unmanagedclass(const char* arg) {}
    void mumble() {}
};

然后你的包装应该像这样:

#pragma managed(push, off)
#include "unmanagedclass.h"
#pragma managed(pop)

using namespace System;
using namespace System::Runtime::InteropServices;

public ref class ManagedWrapper
{
    Unmanagedclass* instance;
public:
    ManagedWrapper(String^ arg) {
        IntPtr mem = Marshal::StringToCoTaskMemAnsi(arg);
        instance = new Unmanagedclass((char*)(void*)mem);
        Marshal::FreeCoTaskMem(mem);
    }
    ~ManagedWrapper() {
        delete instance;
        instance = 0;
    }
    !ManagedWrapper() {
        delete instance;
    }
    void mumble() {
        instance->mumble();
    }
};

这里的方法是非托管类的实例是包装器中的指针。并且只需将托管方法调用委托给非托管方法。是的,有些带字符串的hokeypokey,如图所示。并确保当用户或垃圾收集器绕过它时,会删除此本机实例。

答案 2 :(得分:0)

您正在使用指向on-stack-temp变量的指针。纯粹的运气,如果你一个接一个地调用这些方法,就会指出一些东西。

经过多年的c#comfort,我用c ++编写了一些东西,并且必须告诉你,我现在有同样的问题。

简而言之 - 不要获取临时创建的地址并将其存储在指针中供以后使用。周期。