我试图从系统::String^封送至std::string。
通常,这可以通过marshal_as<T>模板来完成,即
System::String ^managedString = "test";
std::string stdString = marshal_as<std::string>(managedString);但是,如果字符串^是通过引用访问的结构的一部分,则为
value struct SomeStruct {
String ^managedString;
};
auto structHandle = gcnew SomeStruct();
structHandle->managedString = "test";
std::string stdString = marshal_as<std::string>(structHandle->managedString);编译器将抛出以下错误
错误C2665:'msclr::interop::marshal_as‘:三个重载都不能转换所有参数类型
但是,如果结构不是句柄,而是实际的结构,则可以正常工作。
发布于 2015-05-29 13:27:34
auto structHandle = gcnew SomeStruct();这就是问题开始的地方。structHandle引用指向SomeStruct的装箱副本。它需要装箱,因为SomeStruct是一个值类型,结构的副本存储在GC堆上。
您试图使用的marshal_as<>重载的签名是:
marshal_as<std::string,System::String^>(System::String ^const &)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个字段。如果它更大,那么您应该使用引用类型。
https://stackoverflow.com/questions/30529869
复制相似问题