Marshall对象属性生成编译器错误

时间:2017-03-28 06:31:29

标签: c++-cli marshalling

我正在使用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_someStringsomeString都具有String^类型。

THX

1 个答案:

答案 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);