2017-03-28 3 views
1

Je travaille sur une classe Brigde pour travailler avec une bibliothèque C++ non gérée. J'ai un problème avec les éléments suivants (réduit) exemple de code:L'attribut d'objet Marshall génère une erreur de compilation

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); 
     } 
    }; 

Quand j'appelle std::string unManagedString = msclr::interop::marshal_as<std::string>(m_someString); avec l'attribut d'objet m_someString, le compilateur me dit qu'il n'y a pas marshal_as signature de la méthode correspondant. Si j'effectue la même chose avec le paramètre someString, le compilateur ne génère pas d'erreur. Qu'est-ce que je rate? Les deux m_someString et someString ont le type String^.

Thx

Répondre

2

La fonction marshal_as() est pas très sympathique, il manque une surcharge pour permettre ce code à compiler. Vous pouvez affiner le problème en regardant le popup IntelliSense qui montre quelles surcharges sont disponibles. Celui que vous essayez d'utiliser est le 4e:

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

Le diable est dans &, un non géré référence. Oui, une référence non gérée à une référence d'objet géré, halluciné :) Mais parfaitement légale dans C++/CLI, au moment de l'exécution cet argument se transforme en un pointeur brut à la référence de l'objet.

Il aurait compilé si le modèle offrait une surcharge System::String^ % _from_obj. Ce n'est pas le cas. La distinction entre % et & importe beaucoup en C++/CLI, % déclare une référence géré. Appelé une "référence de suivi" dans les docs. Un que le garbage collector connaît et peut mettre à jour lorsqu'il compacte le tas GC. Sinon sémantiquement complètement identique à une référence non gérée.

Que le GC ne peut pas mettre à jour une référence & est le raccrochage ici. Le compilateur interdit carrément de générer des pointeurs non gérés vers les membres d'un type managé, autrement que via pin_ptr <>. Il est beaucoup trop dangereux, le garbage collector peut être lancé à tout moment, même pendant l'exécution de la fonction marshal_as(). Déclenché par, disons, un autre thread qui alloue des objets. Et déplacez l'objet ManagedClass, en invalidant les pointeurs bruts à l'objet. Si la fonction continue d'utiliser le pointeur obsolète au moment de l'exécution, la fonction produira des erreurs et endommage le tas du GC.

La référence d'objet someString est très différente, elle est stockée dans la pile ou dans un registre de processeur et ne peut pas changer lors d'une collecte. Donc, pas de plaintes du compilateur.

Vous avez déjà une bonne solution de contournement ici, l'argument constructeur est bon tel quel. Mais généralement, vous devez en fournir une explicitement et stocker la valeur du membre dans une variable locale. En d'autres termes, écrivez quelque chose comme ceci:

auto temp = this->m_someString; // Intentional temporary 
    auto str = marshal_as<std::string>(temp); 
+0

Essayé, fonctionne. Merci pour la réponse rapide. – Moerwald