Marshall 对象属性生成编译器错误
Marshall object attribute generates compiler error
我正在研究桥 class 以使用非托管 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);
}
};
当我用对象属性 m_someString
调用 std::string unManagedString = msclr::interop::marshal_as<std::string>(m_someString);
时,编译器告诉我没有匹配的 marshal_as
方法签名。如果我对 someString
参数执行相同的操作,编译器不会抛出错误。我错过了什么? m_someString
和 someString
的类型都是 String^
.
感谢
marshal_as()
函数不是很友好,它缺少允许此代码编译的重载。您可以通过查看显示哪些重载可用的 IntelliSense 弹出窗口来解决问题。您尝试使用的是第 4 个:
std::string marshal_as<std::string, System::String^>(System::String^ const & _from_obj)
魔鬼在 &
,一个 unmanaged 参考。是的,对托管对象引用的非托管引用,令人震惊 :) 但在 C++/CLI 中完全合法,在运行时此参数变成指向对象引用的原始指针。
如果模板提供 System::String^ % _from_obj
重载,它就会编译。它没有。 %
和 &
之间的区别在 C++/CLI 中很重要,%
声明了一个 managed 引用。在文档中称为 "tracking reference"。垃圾收集器知道并在压缩 GC 堆时可以更新的一个。否则在语义上与非托管引用完全相同。
GC 无法更新 &
引用是这里的问题。除了通过 pin_ptr<> 之外,编译器完全禁止生成指向托管类型成员的非托管指针。这太危险了,垃圾收集器可以随时启动,即使 marshal_as() 函数正在执行。例如,由另一个分配对象的线程触发。并移动 ManagedClass 对象,使指向该对象的任何原始指针无效。让函数在运行时继续使用过时的指针将使函数产生垃圾并可能破坏 GC 堆。
someString
对象引用非常不同,它存储在堆栈或处理器寄存器中,并且在收集发生时不能更改。所以没有来自编译器的抱怨。
您在这里已经有了一个很好的解决方法,构造函数参数原样很好。但通常您必须显式提供一个并将成员值存储到局部变量中。换句话说,写这样的东西:
auto temp = this->m_someString; // Intentional temporary
auto str = marshal_as<std::string>(temp);
我正在研究桥 class 以使用非托管 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);
}
};
当我用对象属性 m_someString
调用 std::string unManagedString = msclr::interop::marshal_as<std::string>(m_someString);
时,编译器告诉我没有匹配的 marshal_as
方法签名。如果我对 someString
参数执行相同的操作,编译器不会抛出错误。我错过了什么? m_someString
和 someString
的类型都是 String^
.
感谢
marshal_as()
函数不是很友好,它缺少允许此代码编译的重载。您可以通过查看显示哪些重载可用的 IntelliSense 弹出窗口来解决问题。您尝试使用的是第 4 个:
std::string marshal_as<std::string, System::String^>(System::String^ const & _from_obj)
魔鬼在 &
,一个 unmanaged 参考。是的,对托管对象引用的非托管引用,令人震惊 :) 但在 C++/CLI 中完全合法,在运行时此参数变成指向对象引用的原始指针。
如果模板提供 System::String^ % _from_obj
重载,它就会编译。它没有。 %
和 &
之间的区别在 C++/CLI 中很重要,%
声明了一个 managed 引用。在文档中称为 "tracking reference"。垃圾收集器知道并在压缩 GC 堆时可以更新的一个。否则在语义上与非托管引用完全相同。
GC 无法更新 &
引用是这里的问题。除了通过 pin_ptr<> 之外,编译器完全禁止生成指向托管类型成员的非托管指针。这太危险了,垃圾收集器可以随时启动,即使 marshal_as() 函数正在执行。例如,由另一个分配对象的线程触发。并移动 ManagedClass 对象,使指向该对象的任何原始指针无效。让函数在运行时继续使用过时的指针将使函数产生垃圾并可能破坏 GC 堆。
someString
对象引用非常不同,它存储在堆栈或处理器寄存器中,并且在收集发生时不能更改。所以没有来自编译器的抱怨。
您在这里已经有了一个很好的解决方法,构造函数参数原样很好。但通常您必须显式提供一个并将成员值存储到局部变量中。换句话说,写这样的东西:
auto temp = this->m_someString; // Intentional temporary
auto str = marshal_as<std::string>(temp);