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++ Discussion :

String litteral pool


Sujet :

C++

  1. #1
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    91
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 91
    Points : 27
    Points
    27
    Par défaut String litteral pool
    Bonjour a tous, j ai creer ma propre classe MYString, qui fait plein de choses, c est en fait un one-to-one mapping de la classe String de Java, afin de faciliter le portage d application depuis Java.
    Cette classe contient un wchar_t* m_Ptr, qui est le buffer unicode.
    J ai des soucis de performances dans mon application a causes des litteraux.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    MYClass* toto = new MYClass(L"toto");
    Pour le moment je copie le buffer dans m_Ptr.
    Tout mon code prend en parametre des MYString car elle peuvent etre formatees a tout moment, ou stockees, ...
    Mon code comprend beacuoup beaucoup de litteraux, et j aimerais savoir s il est possible d eviter ce memcopy sans ajouter un parametre au constructeur, style :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    MYClass(wchar_t* aStr, bool bIsLitteral = false);
    et creer la string de cette maniere
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    MYClass* toto = new MYClass(L"toto", true);
    true voulant dire qu il sagit d un litteral, donc faire directement m_Ptr = aStr, et ne pas deleter m_Ptr dans le destructeur.
    Inutile de chercher a deleter un litteral, ca crashe, c est stocker a un endroit read/only de la memoire(segment je crois)

    Meme avec cette solution qui evite le memcopy, j ai un autre souci.
    Je fais souvent dans mon code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Context* myContext, ....
    MYValue* value = myContext->getLocal(&MYClass(L"toto", true))
    Context::getLocal(MYString* aString) peut etre appeler soit avec un litteral soit avec une string formatee.
    Quand il s agit un litteral uniquement, je fait toujours MYValue* value = myContext->getLocal(&MYClass(L"toto", true)) et sinon en general appelle :
    myContext->getLocal(myString) , myString vient d ailleur et peut etre n importe quoi, soit un litteral, soit une chaine formatee.
    L ideal serait d avoir toto en static ou variable globale. Comme j ai des centaines de litteraux, je voulais savoir si c est propre creer un tableaux de MYString avec 200 valeur par exemple, et de les stocker selon un index, style :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    enum
    {
    ID_TOTO = 0,
    ID_TITI,
    ID_TUTU ,....
    }
     
    MYString** g_stringLitteralPool = new MYString[200]
    g_stringLitteralPool[ID_TOTO] = new MString(L"toto", true);
    g_stringLitteralPool[ID_TUTU] = new MString(L"tutu", true);, ...
    Pour finalement faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Context* myContext, ....
    MYValue* value = myContext->getLocal(g_stringLitteralPool[ID_TOTO])
    Y a aussi possibiliter de calculer l index de la string dans le tableau a partir du hash du litteral, pour la stocker d une part et pour la recuperer d autre part.
    Je sais pas si c est assez propre de faire ca, mais surtout savoir si dans le concept c est ok.
    Je serait tres reconnaissant si quelqu un a deja eu a faire face a ce genre de probleme de m indiquer quelle a ete sa solution, sinon si vous avez quelconque feedback, c est toujours tres interessant.
    Merci bien

  2. #2
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 611
    Points
    30 611
    Par défaut
    Salut,

    Cela ne va répondre à ta question que de manière détournée, mais... pourquoi t'embêter à faire une telle classe, alors qu'il existe déjà une chaine de caractères gérant les... wchar_t : wstring (disponible dans l'espace de noms std, par inclusion du fichier d'en-tête <string> )

    Après tout, il s'agit ici de porter une application java en C++, ce qui implique une réécriture complète du code (ou d'au moins une grande partie...) .

    Il en aurait peut être été autrement s'il s'agissait d'interfacer java et C++, mais, dans le cas présent, cette solution me semble non seulement viable, mais beaucoup plus simple que toute autre

    [EDIT]Et, comme je n'ai répondu qu'à une partie de la question, pourquoi t'emm...der avec des pointeurs de pointeurs et de l'allocation dynamique pour gérer tes tableaux de chaines de caractères (qui devraient d'ailleurs n'être que des pointeurs, et non des pointeurs de pointeurs )

    Pourquoi ne pas choisir parmi les conteneurs fournis par le standard celui qui s'adaptera le mieux à tes besoins
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  3. #3
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    J ai des soucis de performances dans mon application a causes des litteraux.
    Tu as mesuré pour dire ça ?

    J'ai un peu de mal à l'idée que juste le memcpy de création de tes MyString plombe tes perfs.

  4. #4
    Membre confirmé Avatar de Lavock
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    560
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 560
    Points : 633
    Points
    633
    Par défaut
    Citation Envoyé par kaiser92 Voir le message
    Mon code comprend beacuoup beaucoup de litteraux, et j aimerais savoir s il est possible d eviter ce memcopy sans ajouter un parametre au constructeur, style :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    MYClass(wchar_t* aStr, bool bIsLitteral = false);
    Pas bien compris. La syntaxe ci-dessus est valide.

    Citation Envoyé par kaiser92 Voir le message
    L ideal serait d avoir toto en static ou variable globale. Comme j ai des centaines de litteraux, je voulais savoir si c est propre creer un tableaux de MYString avec 200 valeur par exemple, et de les stocker selon un index, style :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    enum
    {
    ID_TOTO = 0,
    ID_TITI,
    ID_TUTU ,....
    }
     
    MYString** g_stringLitteralPool = new MYString[200]
    g_stringLitteralPool[ID_TOTO] = new MString(L"toto", true);
    g_stringLitteralPool[ID_TUTU] = new MString(L"tutu", true);, ...
    Pour finalement faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Context* myContext, ....
    MYValue* value = myContext->getLocal(g_stringLitteralPool[ID_TOTO])
    Si tu as du temps à perdre, que tu as envie de rendre ton code illisible, et qu'il soit impossible à tout autre personne d'appeler le littéral souhaité oui. Bon, par contre, un enum à plus de 256 valeur, ça craint.
    Malheureusement, j'ai rarement vu du code "sale" conceptuellement bon oO !
    The mark of the immature man is that he wants to die nobly for a cause, while the mark of the mature man is that he wants to live humbly for one.
    --Wilhelm Stekel

  5. #5
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Salut,
    Une réponse possible (modulo les remarques possibles) est de mettre en place un mécanisme de Copy On Write (COW pour les intimes) : ne copier la chaîne que si on a besoin de la modifier; sinon partager le même pointeur (intelligent) avec les autres instances de ta classe. Mais, ça ne règle pas vraiment le cas des litéraux.

  6. #6
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    91
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 91
    Points : 27
    Points
    27
    Par défaut
    Ma classe MYString n utilise pas les std, car mon code doit marcher sur une bonne 10aines de plateformes, donc oublions les std.
    mon code fait une loop sur 500.000 iterations et appelle getLocal(&MYString(L"toto")).
    Il fait 500.000 memcopy de "toto", si bien que le code original Java est plus rapide que mon code natif a cause de ca uniquement.
    La vrai question demeure comment gerer ces litteraux correctement, comme Java le fait?
    Merci

  7. #7
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    getLocal(&MYString(L"toto"))
    Je le sens pas du tout.
    Pourquoi ne pas sortir MyString(L"toto") de la boucle ?
    [EDIT] : venant du monde java, tu as peut être le réflexe de faire des TYPE *var=new TYPE, là où une déclaration sur la pile aurait suffit : TYPE var; Cela peut aussi impacter tes perfs si tu fais beaucoup d'allocation/libération dynamique dans ta boucle.

  8. #8
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Il fait 500.000 memcopy de "toto", si bien que le code original Java est plus rapide que mon code natif a cause de ca uniquement.
    La vrai question demeure comment gerer ces litteraux correctement, comme Java le fait?
    Le COW (Copy On Write) me semble une bonne approche. Par contre, il faut faire attention à ne pas initialiser tes MyString avec des const wchar* qui ne soient pas dans la zone data (ou alors gérer la prise d'ownership, avec tous les problèmes d'allocateur utilisé que ça engendre).

    L'autre question, c'est : tu ne peux pas sortir getLocal(&MyString(L"toto")) de ta boucle ? Ça renvoie un résultat différent à chaque fois ?

  9. #9
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    91
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 91
    Points : 27
    Points
    27
    Par défaut
    impossible de le sortir de la boucle. Donc voila, tu a pas un article sur les COW stp?
    Pour l enum, j ai indiquer une autre possibilite dans mon post initial, si l enum est limité a 256, on peut utiliser le hash de la string pour calculer l index de la string dans le tableau global stockant les MYStrings.
    C'est une solution, il me semble que le Java String litteral pool fonctionne comme ca. Je voudrais attendre le feedback des forumers, analyser toutes les solutions avant de m'avancer.
    Merci de ton aide en tout cas

  10. #10
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    COW : ici. C'est en gros ne copier ta variable que quand tu la modifies, donc tu y accèdes en non constant. Mais pour tes chaînes littérales, la seule façon 'propre' que je vois serait d'utiliser une vraie copie en dehors de la boucle puis le constructeur par copie avec COW dans la boucle :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    MYString str_toto(L"toto"); // fait une copie de la chaîne
    for()
    {
        getLocal(&MYString(str_toto)); // utilise le COW pour la copie de l'objet MyString
    }

  11. #11
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut
    Bonjour,
    Dans ce genre de cas pas commun, je crois que j'utiliserais sans vergogne la classe StringRef de LLVM.

    Edit : J'avais pas vu...
    Ma classe MYString n utilise pas les std, car mon code doit marcher sur une bonne 10aines de plateformes, donc oublions les std.
    Pas de lib standard !? C'est rude. Dans ce cas, StringRef ne convient pas...

  12. #12
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 611
    Points
    30 611
    Par défaut
    Citation Envoyé par kaiser92 Voir le message
    Ma classe MYString n utilise pas les std, car mon code doit marcher sur une bonne 10aines de plateformes, donc oublions les std.
    <snip>
    Qu'importe le nombre de plateformes...

    Ce qui est préfixé par std:: indique que... c'est quelque chose qui a été clairement défini par la norme du standard C++...

    Cela signifie que, pour autant que tu utilise un compilateur qui supporte le standard (ce qui est le cas de quasiment tous les compilateurs datant d'après 1997), les string, wstring, vector et autres joyeusetés fournies par le standard existent et ont un comportement clairement défini.

    Tu ne peux que difficilement faire plus simple et plus portable

    J'aurais accepté cet argument si je t'avais parlé de quelque chose issu de TR1, car il n'a jamais été officialisé, mais pas pour ce qui touche au standard lui-même
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  13. #13
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    91
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 91
    Points : 27
    Points
    27
    Par défaut
    En fait ce n'est pas aussi simple que ca
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    for()
    {
    getLocal(&MYString(L"toto"))
    }
    c'est plutot
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    while
    {
    switch :
    ....
    case : TOTO
    getLocal(&MYString(L"toto"))
    case TITI:
    getLocal(&MYString(L"titi"))
    }
    ....
    Donc il faut la sortir de la boucle, mais dans un autre fichier cpp, et pas que dans un d'ailleurs cette meme chaine toto est utilisée.
    Donc elle doit etre statique et initialisée en global, d'ou ma question sur mon pool. Ou stocker toto, titi, ... proprement et y acceder dans mon code case TOTO par exemple.
    Pour repondre aux std, c'est standard pour le monde entier sauf pour ma boite, qui a décidé de developper pour tous les os une abstraction layer(qui contient une StringRef pas tres performante, donc j'ai refait la mienne).
    Voila tout chers forumers, les contraintes sont les contraintes

  14. #14
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Effectivement, si tu as beaucoup de chaines, peut être qu'un pool sera plus simple. Tu n'as d'ailleurs pas besoin de les allouer dynamiquement :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    MYString g_stringLitteralPool[] = {
     MString(L"toto", true)
    ,MString(L"tutu", true)
    };

  15. #15
    Membre confirmé Avatar de Lavock
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    560
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 560
    Points : 633
    Points
    633
    Par défaut
    Je crois que la réponse est dans c++0x est les expression constantes généralisées... Mais pour des centaines de valeurs ><. Et puis je suis pas sur de ce que tu veux au juste. Si c'est pour éviter l'évaluation de :
    ça pourrait marcher. Pour ça, tu doit définir une classe avec un constructeur en constexpr.
    The mark of the immature man is that he wants to die nobly for a cause, while the mark of the mature man is that he wants to live humbly for one.
    --Wilhelm Stekel

  16. #16
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    91
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 91
    Points : 27
    Points
    27
    Par défaut
    oui c'est exactement ce que je veux faire, un pool de litteral, et je veux le faire proprement.
    Donc avec ton tableau j'initialise toutes les strings au debut, mais quand je veux acceder a tutu depuis getLocal, je fait comment?

    getLocal(g_stringPool[1])??

    Le concept est la, mais comment le faire proprement? Dois-je indexer les strings avec un ID_TUTU = 1, ou bien utiliser le hash code?
    soit
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    getLocal(g_stringPool[ID_TUTU])
    ou bien un truc du genre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    getLocal(StringPoolManager::getString(L"tutu");

  17. #17
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Je ne vois pas l'intérêt du hash code ou de passer par un StringPoolManager (qui te referait perdre du temps). Dans un tableau, l'accès à un élément est constant. Je n'ai pas fait le test mais je ne serais pas surpris que l'accès au énième élément d'un tableau static const soit optimisé par le compilo pour te donner directement l'adresse de l'élément :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    getLocal(&g_stringPool[1]);
    // ou :
    getLocal(&g_stringPool[ID_TUTU]);
    Ton risque est d'avoir une désynchronisation entre ID_TUTU et sa place effective ou de dépasser le tableau.

  18. #18
    Membre confirmé Avatar de Lavock
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    560
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 560
    Points : 633
    Points
    633
    Par défaut
    Si ton allocation est plus lourde que le calcule de ton hash code, avec celui-ci. Mais tes gains ne seront pas formidable amha. Le problème majeur reste l'illisibilité du truc + la volonté, si tu as genre 500 instances à faire à la main...
    The mark of the immature man is that he wants to die nobly for a cause, while the mark of the mature man is that he wants to live humbly for one.
    --Wilhelm Stekel

  19. #19
    Membre confirmé Avatar de Lavock
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    560
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 560
    Points : 633
    Points
    633
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    Je n'ai pas fait le test mais je ne serais pas surpris que l'accès au énième élément d'un tableau static const soit optimisé par le compilo pour te donner directement l'adresse de l'élément...
    Si l'indice est constant, c'est directement remplacer par les compilateur généralement. Sinon, il s'agit d'une vieille addition et d'un return.
    The mark of the immature man is that he wants to die nobly for a cause, while the mark of the mature man is that he wants to live humbly for one.
    --Wilhelm Stekel

  20. #20
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    91
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 91
    Points : 27
    Points
    27
    Par défaut
    Ok donc je definit mes IDs betement :

    ID_TOTO = 0;
    ID_TUTU = 1,
    ID_TITI = 2,....

    J'y ai penser depuis le debut, mais mon chef va me dire que c'est du bricolage.
    Y a pas un truc plus propre, utilisé dans des programmes commerciaux?

Discussions similaires

  1. Réponses: 4
    Dernier message: 18/03/2012, 13h18
  2. Memory pool, std::string et copies
    Par typedef dans le forum SL & STL
    Réponses: 7
    Dernier message: 06/12/2010, 16h44
  3. java String pool
    Par Sun03 dans le forum Débuter avec Java
    Réponses: 2
    Dernier message: 10/06/2010, 16h20
  4. erreur js :unterminated string litteral
    Par Ben_74 dans le forum Général JavaScript
    Réponses: 0
    Dernier message: 25/08/2009, 19h03
  5. String Grid et choix d'une couleur pour une ligne
    Par Gigottine dans le forum C++Builder
    Réponses: 12
    Dernier message: 17/05/2002, 16h23

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