从System :: String ^从结构句柄成员向std :: string封送 [英] Marshal to std::string from System::String^ member of struct handle

查看:157
本文介绍了从System :: String ^从结构句柄成员向std :: string封送的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正试图从System :: String ^编组为std :: string.

I am trying to marshal to a std::string from a System::String^.

通常,这可以通过marshal_as<T>模板完成,即

Usually this can be done with the marshal_as<T> template i.e.

System::String ^managedString = "test";
std::string stdString = marshal_as<std::string>(managedString);

但是,如果String ^是引用(即引用)所访问的结构的一部分,则

But if the String^ is part of a struct that is accessed by reference i.e.

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':3个重载都不 可以转换所有参数类型

error C2665: 'msclr::interop::marshal_as' : none of the 3 overloads could convert all the argument types

但是,如果该结构不是句柄,而是实际的结构,则可以正常工作.

However if the struct is not a handle, but the actual struct, it works fine.

推荐答案

   auto structHandle = gcnew SomeStruct();

这是问题开始的地方. structHandle 引用指向SomeStruct的盒装副本.由于SomeStruct是值类型,因此需要将其装箱,该结构的副本存储在GC堆上.

This is where the problem started. The structHandle reference points to a boxed copy of SomeStruct. It needs to be boxed because SomeStruct is a value type, the copy of the struct is stored on the GC heap.

您尝试使用的marshal_as<>重载的签名是:

The signature of the marshal_as<> overload you are trying to use is:

   marshal_as<std::string,System::String^>(System::String ^const &)

const&是问题,您无法获取对该成员的非托管引用,其地址不稳定(不是const),因为垃圾收集器可以在执行marshal_as<的同时移动对象.当marshal_as现在取消引用不再存在的对象时,这将导致灾难.

The const& is the problem, you cannot get an unmanaged reference to the member, its address is not stable (not const) since the garbage collector can move the object while marshal_as<> is executing. That would cause disaster when marshal_as now dereferences an object that's no longer there.

一种解决方法是在尝试转换引用之前,将引用从盒装对象中复制出来:

A workaround is to copy the reference out of the boxed object before you try to convert it:

   structHandle->managedString = "test";
   String^ refCopy = structHandle->managedString;
   std::string stdString = marshal_as<std::string>(refCopy);   // fine

但这只是针对您代码中实际问题的一种破解方法.存在值类型以提高代码效率,从而允许将结构存储在堆栈帧或CPU寄存器中.就像本地C ++对象一样.通过将结构装箱,您将失去这一优势.换句话说,如果您不打算将value struct视为值,则毫无意义地声明它.正确使用它进行正确的修复:

But that's just a hack around the real problem in your code. Value types exist to make code efficient, allowing structures to be stored on the stack frame or a CPU register. Just like a native C++ object. You are throwing that advantage away by boxing the struct. Or in other words, there just wasn't any point in declaring a value struct if you are not going to treat it as a value. Use it properly for the correct fix:

    SomeStruct value;
    value.managedString = "test";
    auto result = marshal_as<std::string>(value.managedString);  // fine

或者,如果您在函数参数上错误地使用^来获得引用,则重写为:

Or if you got the reference by mistakenly using ^ on a function argument then rewrite to:

    void SomeFunction(SomeStruct% arg) {
        auto nativeString = marshal_as<std::string>(arg.managedString);
        '' etc..
    }

请注意使用%而不是^通过引用传递变量.但是不要那样做,值类型的要点是复制值比必须取消引用指针来获取值要便宜.确保您的值类型不太大,最多不能包含4个字段.如果较大,则应使用引用类型.

Note the use of % instead of ^ to pass a variable by reference. But don't do that, the point of a value type is that it is cheaper to copy the value than having to dereference a pointer to obtain the value. Make sure your value type is not too big, it should not have more than 4 fields. If it is bigger then you should use a reference type.

这篇关于从System :: String ^从结构句柄成员向std :: string封送的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆