c++ - 如何将托管值类型成员添加到非托管类?

标签 c++ c++-cli

我正在尝试创建一个名为 MyNativeClass 的 native C++ 类,它可以由非托管代码使用。 MyNativeClass 的成员函数是使用托管代码实现的。此外,托管代码需要一个 System::Numerics::BigInteger 对象,但是当我尝试将 System::Numerics::BigInteger bi_ 字段添加到 MyNativeClass,我得到

error C3265: cannot declare a managed 'bi_' in an unmanaged 'MyNativeClass'

这是一个简化的代码 list ,它演示了我正在努力实现的目标:

mynativeclass.h

class MyNativeClass
{
    //...

public:
    MyNativeClass();
    //...

private:
    System::Numerics::BigInteger bi_;

    //...
};

mynativeclass.cc

MyNativeClass::MyNativeClass()
    : bi_(BigInteger::Zero)
{
    //...
}

我不确定为什么不允许这样做。

有办法吗?

最佳答案

您不能在 native 类型中包含托管数据。原因是 native 类型的对象在垃圾收集器的范围之外,并且不会阻止托管对象死亡。

“我知道”,你说。 “但是值类型并没有保存在托管堆上,也不需要垃圾收集器跟踪它们的生命周期!”千真万确。但是托管值类型可能包含引用类型的句柄。如果垃圾收集器看不到它们,就无法保持它们的引用(或在分代垃圾收集器压缩堆/将对象提升到更高的代时调整它们)。

可以将可 blittable 数据(不包含句柄)直接存储在 native 内存中。事实上,这对于具有双重标识的原始类型是允许的(例如, native int == System.Int32 )。但它不允许用于任何复合类型,大概是为了保持语言规则简单。和 BitInteger无论如何都不允许,因为它确实需要保留可变大小内容区域的句柄(使用 dotPeek 或引用源,它显示为 array<unsigned>^ )以支持任意精度。

解决方法是使用 GCHandle垃圾收集器的功能,使对象在垃圾收集器的范围之外保持事件状态。但是用 GCHandles 替换值类中的所有句柄会导致内存中布局不兼容,因此它们实际上不再是同一类型。最简单的解决方案是使用 gcroot<> (这是 GCHandle 的一个很好的 C++/CLI 接口(interface))到一个引用类类型,并将您的托管值类型粘贴在其中。

C++/CLI 团队最初尝试允许混合类型,但事情变得复杂并以您现在看到的分离规则告终。有一篇关于此的相当不错的博客文章,但我现在找不到了。

关于c++ - 如何将托管值类型成员添加到非托管类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32704915/

相关文章:

string - C++/CLI 字符串转换

c# - 适用于 C# 应用程序的 AnyCPU/x86/x64 及其 C++/CLI 依赖项

C++/CLI 前向声明问题

c++ - MainWindow 中的 QTableView 和选项卡排序

c++ - 管理生成文件中的依赖关系复杂性

c++-cli - 在 CLI/C++ 中创建以下通用 IEnumerable?

visual-studio - 编译 C++/CLI 时缺少 MSBuild 任务

c++ - 垃圾邮件 std::move 是要走的路吗?

c++ - C++中接口(interface)类和实现类的并行继承

c++ - 从声明为 std::set<std::shared_ptr<Edge>> edges_ 的 edges_ 中删除边;