我正在使用brigde类来处理非托管c ++库。我对以下(简化)示例代码有疑问:
ref class ManagedClass
{
private:
UnManagedClass* m_UnManaged;
String^ m_someString;
public:
UserAgent_Managed(String^ someString)
{
m_someString = someString;
// Compiler error
// Severity Code Description Project File Line Suppression State Error C2665 'msclr::interop::marshal_as': none of the 3 overloads could convert all the argument
// types
std::string unManagedString = msclr::interop::marshal_as<std::string>(m_someString);
// Following works
// std::string unManagedString = msclr::interop::marshal_as<std::string>(someString);
m_UnManaged = new UnManagedClass(unManagedString);
}
};
当我使用对象属性std::string unManagedString = msclr::interop::marshal_as<std::string>(m_someString);
调用m_someString
时,编译器会告诉我没有匹配的marshal_as
方法签名。如果我使用someString
参数执行相同操作,则编译器不会抛出错误。我错过了什么? m_someString
和someString
都具有String^
类型。
THX
答案 0 :(得分:2)
marshal_as()
函数不是很友好,它缺少允许此代码编译的重载。您可以通过查看显示哪些重载可用的IntelliSense弹出窗口来解决问题。你试图使用的是第四个:
std::string marshal_as<std::string, System::String^>(System::String^ const & _from_obj)
恶魔在&
,非托管参考。是的,对托管对象引用的非托管引用,请注意:)但在C ++ / CLI中完全合法,在运行时,此参数将变为指向对象引用的原始指针。
如果模板提供System::String^ % _from_obj
重载,它将编译。它没有。 %
和&
之间的区别在C ++ / CLI中很重要,%
声明了托管引用。被称为跟踪参考&#34;在文档中。垃圾收集器知道的一个,并且在压缩GC堆时可以更新。否则在语义上与非托管引用完全相同。
GC无法更新&
引用是这里的挂起。编译器完全禁止生成托管类型成员的非托管指针,而不是通过pin_ptr&lt;&gt;。这太危险了,即使marshal_as()函数正在执行,垃圾收集器也可以随时启动。例如,由另一个分配对象的线程触发。并移动ManagedClass对象,使对象的任何原始指针无效。让函数在运行时继续使用过时的指针会使函数产生垃圾并可能破坏GC堆。
someString
对象引用非常不同,它存储在堆栈或处理器寄存器中,并且在发生集合时无法更改。所以没有来自编译器的投诉。
你已经有了一个很好的解决方法,构造函数参数是原样的。但通常您必须明确提供一个并将成员值存储到局部变量中。换句话说,写下这样的东西:
auto temp = this->m_someString; // Intentional temporary
auto str = marshal_as<std::string>(temp);