auto structHandle = gcnew SomeStruct();
这就是问题开始的地方。这结构体句柄参考点boxedSomeStruct 的副本。它需要装箱,因为 SomeStruct 是一个值类型,该结构的副本存储在 GC 堆上。
您尝试使用的 marshal_as 重载的签名是:
marshal_as<std::string,System::String^>(System::String ^const &)
The const&
问题是,您无法获得对该成员的非托管引用,其地址不稳定(不是 const),因为垃圾收集器可以在执行 marshal_as 时移动该对象。当 marshal_as 现在取消引用不再存在的对象时,这将导致灾难。
解决方法是在尝试转换之前将引用从装箱对象中复制出来:
structHandle->managedString = "test";
String^ refCopy = structHandle->managedString;
std::string stdString = marshal_as<std::string>(refCopy); // fine
但这只是针对代码中真正问题的一种破解。值类型的存在是为了提高代码效率,允许将结构存储在堆栈帧或 CPU 寄存器上。就像本机 C++ 对象一样。通过对结构进行装箱,您将放弃这一优势。或者换句话说,宣布一个没有任何意义value struct
如果您不打算将其视为一种价值。正确使用它来进行正确的修复:
SomeStruct value;
value.managedString = "test";
auto result = marshal_as<std::string>(value.managedString); // fine
或者,如果您通过在函数参数上错误地使用 ^ 获得引用,则重写为:
void SomeFunction(SomeStruct% arg) {
auto nativeString = marshal_as<std::string>(arg.managedString);
'' etc..
}
请注意使用 % 而不是 ^ 通过引用传递变量。但不要这样做,值类型的要点是复制值比取消引用指针来获取值更便宜。确保您的值类型不要太大,字段不应超过 4 个。如果它更大,那么您应该使用引用类型。