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_someStringsomeString 的类型都是 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);