IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++/CLI Discussion :

convertir gcroot<String^> en String^%


Sujet :

C++/CLI

  1. #1
    Membre averti

    Profil pro
    Étudiant
    Inscrit en
    Décembre 2004
    Messages
    499
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2004
    Messages : 499
    Points : 422
    Points
    422
    Par défaut convertir gcroot<String^> en String^%
    Salut,

    Sémantiquement le but est de faire ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    #include <gcroot.h>
     
    void Test (String ^% k) {
    	k = "apres";
    }
    int main(array<System::String ^> ^args)
    {
    	gcroot<String^> ungcroot = "avant";
    	Test(ungcroot);
            String ^res = ungcroot; // res == "apres"
            return 0;
    }
    Sauf que ça ne fonctionne pas.
    La solution que j'ai trouvée :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
     
    #include <gcroot.h>
    template <typename T> union Dummy {
       // pour récupérer le champ caché _handle de la structure gcroot
    	gcroot<T>& g;
    	void *ptr;
    	Dummy(gcroot<T>& g) : g(g) {}
    };
    template <typename T> T% Gcroot2TrackingReference(gcroot<T>& x) {
    	Dummy<T> d(x);
            /// x est un pointeur sur gcroot,
            /// un gcroot est un pointeur sur Object^
    	return **(T**) d.ptr; // d'où ce cast 
    }
     
    void Test (String ^% k) {
    	k = "apres";
    }
    int main(array<System::String ^> ^args)
    {
    	gcroot<String^> s = "avant";
    	Test(Gcroot2TrackingReference(s));
    	String^ res = s; // res == "apres"
            return 0; 
    }
    Une autre solution ?

    Je peux argumenter sur le fait que c'est 100% safe de faire ça avec l'implémentation actuelle de la CLR :

    • un Object ^ est un pointeur dont l'emplacement (l'adresse) est toujours connue de la CLR, qui modifiera sa valeur si elle le souhaite avec ses histoires de déplacement d'objets dans le tas managé. Seules les fonctions __clrcall peuvent mettre un Object^ sur la pile C++ habituelle : la CLR sait retrouver toutes les fonctions __clrcall de la callstack.
    • un Object^% est une référence sur Object^ donc c'est l'adresse d'un Object^. Deux cas se présentent : le Object^ est sur la pile C++ et ne bougera pas, le Object^% est alors une référence C++ normale. Ou bien le Object^ est un champ d'un objet managé, et alors Object^% est une tracking référence. La CLR n'a pas de raison de présumer d'où est la pile C++. Elle sait juste reconnaître quand une adresse est dans le tas managé ou non. Un Object^% peut lui être situé n'importe où, et l'Object^ référencé également (alors que l'Object lui est forcément dans le tas managé).
    • un gcroot est un pointeur sur Object^, Object^ qui lui est situé à un emplacement (plus ou moins alloué dynamiquement) connu de la CLR.
      le gcroot peut être situé n'importe où, comme un Object^%.
    • La seule différence entre un gcroot et une tracking reference c'est qu'un gcroot pointe toujours sur un Object^ situé dans cet emplacement connu de la CLR et alloué dynamiquement, alors qu'une tracking référence pointe sur un Object^ situé n'importe où.
    • Donc caster un gcroot en Object^% n'est pas unsafe. L'inverse l'est peut-être.

  2. #2
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    J'ai eu une idée pour le faire avec un objet intermédiaire (enfin, deux):
    Code C++/CLI : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    template<class T>
    class GCRootRef
    {
    public: //Note: J'ai une MethodAccessException si c'est private
    	ref class RefHolder
    	{
    	public:
    		T obj;
    	};
    private:
    	gcroot<T>& rs;
    	gcroot<RefHolder^> holder;
    public:
    	GCRootRef(gcroot<T>& rs) : rs(rs), holder(gcnew RefHolder)
    	{
    		holder->obj = rs;
    	}
    	~GCRootRef()
    	{
    		rs = holder->obj;
    	}
    	operator T%() { return holder->obj; }
    };
     
     
    void FonctionRef(System::String^% strref)
    {
    	strref = L"world";
    }
     
    void FonctionTest(void)
    {
    	gcroot<System::String^> str = L"Hello";
    	FonctionRef(GCRootRef<System::String^>(str));
    	System::Console::WriteLine(str);
    }
    Bien sûr, ça n'offre pas vraiment une référence vers le gcroot, seulement une référence vers un pointeur managé dont la modification sera répercutée sur l'original.
    D'après Stack Overflow, il n'y a pas de problème de durée de vie.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

Discussions similaires

  1. [2.0] Convertir une cle primaire byte[] en string
    Par freddyboy dans le forum Accès aux données
    Réponses: 14
    Dernier message: 20/12/2010, 12h05
  2. Convertir et formater un Double en String
    Par Faiche dans le forum Débuter avec Java
    Réponses: 3
    Dernier message: 25/06/2009, 14h48
  3. Réponses: 15
    Dernier message: 30/09/2008, 14h43
  4. Convertir un flux ascii pour un String
    Par bubulemaster dans le forum Débuter
    Réponses: 1
    Dernier message: 24/04/2008, 13h31
  5. Réponses: 4
    Dernier message: 13/07/2006, 11h23

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo