在本机 C++ 函数中是否需要 gcroot?
Is gcroot necessary inside a native C++ function?
我是 c++/cli 编程的新手,今天我在我的一个项目中遇到 gcroot
并对其用法感到困惑。
我发现 gcroot
是 GChandle
的包装器,它通知垃圾收集器正在引用托管对象,因此该对象不会被删除。
因此使用 gcroot
在本机 class 中声明属性以保存对托管对象的引用是有意义的。但是我发现 gcroot
也在项目中到处使用,如下所示:
int NativeFunction()
{
gcroot<ManagedType^> xx = gcnew ManagedType();
return xx->FunctionCalled();
}
这种实施方式是好的做法吗?这里有必要用gcroot
吗?
如果我在没有 gcroot
的情况下声明 xx
会怎样,例如:
ManagedType^ xx = gcnew ManagedType();
它会产生任何问题吗?
这里有多个级别的错误。从完全错误的地方开始,你是对的,使用 gcroot<>
是完全没有必要的,而且是有害的。它是 GCHandle 的包装器,您将在运行时调用 GCHandle::Alloc()、GCHandle::ToIntPtr()、GCHandle::FromIntPtr() 和 GCHandle::Free()。没有任何好处,GC 已经可以在没有任何帮助的情况下找到 ManagedType 对象引用。即时编译器的主要职责。你的替代品没问题。
那么问题来了,无参数的 ManagedType 构造函数执行了什么样的魔法?您必须看一下,这段代码的作者很有可能只是没有意识到 static
关键字应该有用。所以他可以简单地写 ManagedType::FunctionCalled() 并避免完全分配一个对象。过分依赖 gcroot<> 拐杖肯定会阻止他看到这一点。
然后是调用此 "native code" 的讨厌问题。不是,它必须使用 /clr 或 #pragma managed in effect 进行编译。这会生成必须在运行时即时编译的 MSIL。就像托管代码一样。但是如果没有托管代码的好处,它就像本机代码一样无法验证。和 none 本机代码的好处一样,您不会得到优化器的额外喜爱。当整个库使用 /clr 进行编译时,这往往会变得更加糟糕。不幸的是,设计师做得太好了,以至于很容易注意到这一点,您只会观察到性能的损失。
正确的方法是按照本机代码始终执行此操作的方式执行此操作。带有函数指针。您可以使用 Marshal::GetFunctionPointerForDelegate() 获得您需要的那个。然而,正确编写更难,除非您需要解决性能问题,否则您可能不应该考虑使用工作代码。
我是 c++/cli 编程的新手,今天我在我的一个项目中遇到 gcroot
并对其用法感到困惑。
我发现 gcroot
是 GChandle
的包装器,它通知垃圾收集器正在引用托管对象,因此该对象不会被删除。
因此使用 gcroot
在本机 class 中声明属性以保存对托管对象的引用是有意义的。但是我发现 gcroot
也在项目中到处使用,如下所示:
int NativeFunction()
{
gcroot<ManagedType^> xx = gcnew ManagedType();
return xx->FunctionCalled();
}
这种实施方式是好的做法吗?这里有必要用gcroot
吗?
如果我在没有 gcroot
的情况下声明 xx
会怎样,例如:
ManagedType^ xx = gcnew ManagedType();
它会产生任何问题吗?
这里有多个级别的错误。从完全错误的地方开始,你是对的,使用 gcroot<>
是完全没有必要的,而且是有害的。它是 GCHandle 的包装器,您将在运行时调用 GCHandle::Alloc()、GCHandle::ToIntPtr()、GCHandle::FromIntPtr() 和 GCHandle::Free()。没有任何好处,GC 已经可以在没有任何帮助的情况下找到 ManagedType 对象引用。即时编译器的主要职责。你的替代品没问题。
那么问题来了,无参数的 ManagedType 构造函数执行了什么样的魔法?您必须看一下,这段代码的作者很有可能只是没有意识到 static
关键字应该有用。所以他可以简单地写 ManagedType::FunctionCalled() 并避免完全分配一个对象。过分依赖 gcroot<> 拐杖肯定会阻止他看到这一点。
然后是调用此 "native code" 的讨厌问题。不是,它必须使用 /clr 或 #pragma managed in effect 进行编译。这会生成必须在运行时即时编译的 MSIL。就像托管代码一样。但是如果没有托管代码的好处,它就像本机代码一样无法验证。和 none 本机代码的好处一样,您不会得到优化器的额外喜爱。当整个库使用 /clr 进行编译时,这往往会变得更加糟糕。不幸的是,设计师做得太好了,以至于很容易注意到这一点,您只会观察到性能的损失。
正确的方法是按照本机代码始终执行此操作的方式执行此操作。带有函数指针。您可以使用 Marshal::GetFunctionPointerForDelegate() 获得您需要的那个。然而,正确编写更难,除非您需要解决性能问题,否则您可能不应该考虑使用工作代码。