如何将托管值类型成员添加到非托管类
How to add a managed value type member to an unmanaged class?
我正在尝试创建一个名为MyNativeClass
的本机c++类,可由非托管代码使用。MyNativeClass
的成员函数使用托管代码实现。此外,托管代码需要一个System::Numerics::BigInteger
对象,但是当我试图将System::Numerics::BigInteger bi_
字段添加到MyNativeClass
时,我得到
错误C3265:不能在非托管的MyNativeClass中声明托管的'bi_'
下面是一个简化的代码清单,演示了我想要实现的目标:
mynativeclass.h
class MyNativeClass
{
//...
public:
MyNativeClass();
//...
private:
System::Numerics::BigInteger bi_;
//...
};
mynativeclass.cc
MyNativeClass::MyNativeClass()
: bi_(BigInteger::Zero)
{
//...
}
我不知道为什么这是不允许的。
有办法做到这一点吗?
本机类型中不能有托管数据。原因是本机类型的对象不在垃圾收集器的范围内,并且不能防止托管对象死亡。
"我知道",你说。"但是值类型不会保存在托管堆上,也不需要垃圾收集器跟踪它们的生命周期!"完全正确。但是托管值类型可能包含引用类型的句柄。如果垃圾收集器看不到它们,它就不能保持它们的引用存活(或者在分代垃圾收集器压缩堆/将对象提升到更高代时调整它们)。
可以将位元数据(不包含句柄)直接存储在本机内存中。事实上,对于具有双重标识(例如,原生int
== System.Int32
)的基本类型,这是允许的。但是对于任何复合类型都不允许这样做,大概是为了保持语言规则的简单性。而且BitInteger
无论如何也不被允许,因为它确实需要保持一个可变大小的内容区域的句柄(使用dotPeek或参考源,它被揭示为array<unsigned>^
),以支持任意精度。
解决方法是使用垃圾收集器的GCHandle
特性,使对象在垃圾收集器的领域之外保持活动状态。但是用GCHandles替换值类中的所有句柄会导致不兼容的内存布局,因此它实际上不再是相同的类型了。最简单的解决方案是使用gcroot<>
(这是GCHandle
的一个很好的c++/CLI接口)来引用类类型,并将您的托管值类型粘贴在其中。
c++/CLI团队最初试图允许混合类型,但事情变得复杂,最终以您现在看到的分离规则告终。有一篇很好的博客文章是关于这个的,但是我现在找不到
- 将成员变量添加到共享库中的类中,不会破坏二进制兼容性吗
- 添加静态constexpr成员是否会更改结构/类的内存映射
- 我可以在 C++ 中将数据成员/变量从其定义之外添加到结构中吗?
- 将私有数据成员添加到野牛生成的类中
- 如何在友元函数中使用静态成员而不添加前缀 [类名]::
- 如何添加依赖于类本身的模板成员变量
- '将成员函数仅添加到类的专用模板
- 如何将任何值转换为对象并使用 boost::p roperty_tree json 添加成员
- 如何为内置类型添加成员功能,例如C 中的整数
- 基于模板参数添加成员函数和成员变量
- 如何使用std::bind向信使系统添加成员回调
- 是否为模板类的某些模板参数添加成员
- 添加成员的声明会导致其隐式初始化
- 具有宏添加成员和影响构造函数
- 如何在添加成员时维护结构的初始化
- 向绑定到Lua的c++类添加成员函数
- 添加成员提升::p tr_vector<>
- 在实现文件中添加成员函数
- 在大解决方案中向类添加成员时发生堆栈溢出错误
- 为第三个库类型添加成员字段