Question

Je n'ai pas beaucoup utilisé le C ++ dans le passé et j'ai récemment beaucoup travaillé en C #, et j'ai vraiment du mal à revenir à la base du C ++. Cela est particulièrement délicat, car le travail exige qu'aucune des constructions C ++ les plus pratiques ne puisse être utilisée. Par conséquent, toutes les chaînes doivent être des caractères char *, et aucune liste n'est prévue pour les listes STL.

Ce que j'essaie actuellement de faire est de créer une liste de chaînes, quelque chose qui ne me prendrait pas du tout de temps en utilisant STL ou en C #. En gros, je veux avoir une fonction telle que:

char **registeredNames = new char*[numberOfNames];

Ensuite,

RegisterName(const * char const name, const int length)
{
    //loop to see if name already registered snipped
    if(notFound)
    {
        registeredNames[lastIndex++] = name;
    }

}

ou, s'il s'agissait de C # ...

if(!registeredNames.Contains(name))
{
    registeredNames.Add(name);
}

et je me rends compte que ça ne marche pas. Je sais que la nature constante des variables passées (un pointeur constant et une chaîne constante) rend la tâche plutôt difficile, mais mon problème fondamental est que j’ai toujours évité cette situation par le passé en utilisant des listes STL, etc. dû travailler dessus!

Était-ce utile?

La solution

Vous devrez probablement utiliser strcmp pour voir si la chaîne est déjà stockée:

for (int index=0; index<=lastIndex; index++)
{
  if (strcmp(registeredNames[index], name) == 0)
  {
    return; // Already registered
  }
}

Ensuite, si vous avez vraiment besoin de stocker une copie de la chaîne, vous devrez alors allouer un tampon et copier les caractères.

char* nameCopy = malloc(length+1);
strcpy(nameCopy, name);
registeredNames[lastIndex++] = nameCopy;

Vous n'avez pas indiqué si votre entrée est terminée par la valeur NULL. Si ce n'est pas le cas, une attention particulière est nécessaire, et strcmp / strcpy ne conviendra pas.

Autres conseils

Il existe des raisons légitimes d’éviter le traitement STL. Lorsque vous travaillez dans des environnements fixes où la mémoire ou la vitesse est primordiale, il est parfois difficile de savoir ce qui se passe sous le capot avec STL. Oui, vous pouvez écrire vos propres allocateurs de mémoire, et oui, la vitesse ne pose généralement pas de problème, mais il existe des différences entre les implémentations STL d'une plate-forme à l'autre, et ces différences peuvent être subtiles et potentiellement buggées. La mémoire est peut-être ma plus grande préoccupation lorsque je pense à l'utiliser.

La mémoire est précieuse et son utilisation doit être contrôlée de près. À moins que vous n'ayez emprunté cette voie, ce concept pourrait ne pas avoir de sens, mais c'est vrai. Nous autorisons l'utilisation de la STL dans des outils (en dehors du code du jeu), mais cela est interdit à l'intérieur du jeu. Un autre problème connexe est la taille du code. Je ne suis pas certain de savoir à quel point STL peut contribuer à la taille des exécutables, mais nous avons constaté une nette augmentation de la taille du code lorsque nous utilisons STL. Même si votre exécutable est " only " 2M plus gros, c'est 2M moins de RAM pour autre chose pour votre jeu.

STL est sympa à coup sûr. Mais il peut être abusé par les programmeurs qui ne savent pas ce qu’ils font. Ce n'est pas intentionnel, mais cela peut créer de mauvaises surprises lorsque vous ne voulez pas les voir (encore une fois, problèmes de mémoire et de performances)

Je suis certain que votre solution est proche.

for ( i = 0; i < lastIndex; i++ ) {
    if ( !strcmp(&registeredNames[i], name ) {
        break;    // name was found
    }
}
if ( i == lastIndex ) {
    // name was not found in the registeredNames list
    registeredNames[lastIndex++] = strdup(name);
}

Vous pourriez ne pas vouloir utiliser strdup. C'est simplement un exemple de la façon de stocker le nom donné à votre exemple. Vous voudrez peut-être vous assurer que vous ne voulez pas allouer vous-même d'espace pour le nouveau nom ou utiliser une autre construction de mémoire qui est peut-être déjà disponible dans votre application.

Et s'il vous plaît, n'écrivez pas une classe de chaînes. J'ai cité les classes de chaînes comme étant peut-être le pire exemple de la non-restructuration d'une construction C de base en C ++. Oui, la classe string peut vous cacher beaucoup de détails intéressants, mais ses habitudes d'utilisation de la mémoire sont terribles et celles-ci ne s'intègrent pas bien dans un environnement de console (c'est-à-dire ps3 ou 360, etc.). Il y a environ 8 ans, nous avons fait la même chose. Plus de 200 000 allocations de mémoire avant d'appuyer sur le menu principal. La mémoire était terriblement fragmentée et nous ne pouvions pas intégrer le reste du jeu dans l'environnement fixe. Nous avons fini par le déchirer.

La conception de classe est idéale pour certaines choses, mais ce n’est pas l’une d’elles. C’est un avis, mais il est basé sur une expérience réelle.

Si la portabilité pose problème, vous pouvez consulter STLport .

Pourquoi ne pouvez-vous pas utiliser la STL?

Quoi qu'il en soit, je vous conseillerais de mettre en œuvre une classe de chaîne simple et des modèles de liste de votre choix. De cette façon, vous pouvez utiliser les mêmes techniques que d'habitude et garder le pointeur et la gestion de la mémoire limités à ces classes. Si vous imitez la STL, ce serait encore mieux.

Si vous ne pouvez vraiment pas utiliser stl (et je regrette de croire que c'était le cas lorsque j'étais dans l'industrie du jeu vidéo), ne pouvez-vous pas créer votre propre classe de cordes? La classe de base la plus élémentaire allouait de la mémoire lors de la construction et de l'affectation et gérait la suppression dans le destructeur. Plus tard, vous pourrez ajouter des fonctionnalités supplémentaires selon vos besoins. Totalement portable, et très facile à écrire et test unitaire.

Travailler avec char * nécessite de travailler avec les fonctions C. Dans votre cas, vous avez vraiment besoin de copier les chaînes. Pour vous aider, vous avez la fonction strndup. Ensuite, vous devrez écrire quelque chose comme:

void RegisterName(const char* name)
{
  // loop to see if name already registered snipped
  if(notFound)
  {
    registerNames[lastIndex++] = stdndup(name, MAX_STRING_LENGTH);
  }
}

Ce code suppose que votre tableau est assez grand.

Bien sûr, le mieux serait d’implémenter correctement votre propre chaîne, tableau et liste, ... ou de convaincre votre patron que la STL n’est plus un mal!

Edit: Je suppose que j'ai mal compris votre question. Je ne suis au courant d'aucun problème de constance dans ce code.

Je fais cela de la tête mais cela devrait être à peu près correct:

static int lastIndex = 0;
static char **registeredNames = new char*[numberOfNames];

void RegisterName(const * char const name)
{
    bool found = false;
    //loop to see if name already registered snipped
    for (int i = 0; i < lastIndex; i++)
    {
        if (strcmp(name, registeredNames[i] == 0))
        {
            found = true;
            break;
        }
    }

    if (!found)
    {
        registeredNames[lastIndex++] = name;
    }
}

Je peux comprendre pourquoi vous ne pouvez pas utiliser STL - la plupart gonflent terriblement votre code. Cependant, il existe des implémentations pour les programmeurs de jeux par les programmeurs de jeux - RDESTL est l'une de ces bibliothèques.

Utilisation de:

const char **registeredNames = new const char * [numberOfNames];

vous permettra d'affecter un const * char const à un élément du tableau.

Juste par curiosité, pourquoi "fonctionne-t-il sans qu'aucune des constructions C ++ les plus pratiques ne puisse être utilisée"?

Toutes les approches suggérées sont valables. Mon point est que si C # est attractif, reproduisez-le, créez vos propres classes / interfaces pour présenter la même abstraction, c.-à-d. une simple classe de liste chaînée avec les méthodes Contains et Add, en utilisant exemple de code fourni par d’autres réponses, cela devrait être relativement simple.

L'un des avantages du C ++ est généralement que vous pouvez lui donner l'apparence et agir comme vous le souhaitez. Si un autre langage a une excellente implémentation de quelque chose, vous pouvez généralement le reproduire.

J'ai utilisé cette classe String pendant des années.

http://www.robertnz.net/string.htm

Il fournit pratiquement toutes les fonctionnalités du La chaîne STL est implémentée comme une vraie classe et non comme un modèle et n'utilise pas STL.

C’est un cas clair de rouler vous-même. Et faites de même pour une classe de vecteurs.

  • Faites-le avec la programmation test-first.
  • Gardez les choses simples.

Évitez que les références ne comptent le tampon de chaîne si vous êtes dans un environnement MT.

Si vous n'êtes pas inquiet pour les conventions et que vous voulez juste faire le travail, utilisez realloc. Je fais ce genre de chose pour les listes tout le temps, ça ressemble à ça:

T** list = 0;
unsigned int length = 0;

T* AddItem(T Item)
{
 list = realloc(list, sizeof(T)*(length+1));
 if(!list) return 0;
 list[length] = new T(Item);
 ++length;
 return list[length];
}

void CleanupList()
{
 for(unsigned int i = 0; i < length; ++i)
 {
  delete item[i];
 }
 free(list)
}

Vous pouvez faire plus, par exemple seulement realloc à chaque fois que la taille de la liste double, fonctions permettant de supprimer des éléments de liste par index ou en vérifiant l’égalité, créer une classe de modèle pour la gestion des listes, etc. Je suis au travail et je ne peux pas simplement le copier-coller ici). Pour être tout à fait honnête, cela ne sera probablement pas plus performant que l’équivalent STL, bien que cela puisse égaler ses performances si vous faites beaucoup de travail ou si vous avez une mise en œuvre particulièrement médiocre de STL.

Malheureusement, C ++ n’a pas d’opérateur à renouveler / redimensionner pour remplacer realloc, ce qui serait très utile.

Oh, et pardon si mon code est corrigé en erreur, je l'ai simplement extrait de la mémoire.

const correct est toujours const correct, que vous utilisiez la STL ou non. Je crois que ce que vous recherchez, c’est de faire de registeredNames un const char ** afin que l’affectation à registeredNames [i] (qui est un const char * ) fonctionne.

De plus, est-ce vraiment ce que vous voulez faire? Il semble que faire une copie de la chaîne soit probablement plus approprié.

En outre, vous ne devriez pas songer à la stocker dans une liste, étant donné l’opération que vous faites, un ensemble serait mieux.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top