Erreurs par milliers (Qt)

Pouknouki Messages postés 45 Date d'inscription jeudi 21 juillet 2011 Statut Membre Dernière intervention 27 août 2014 - 5 août 2013 à 19:47
cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 - 6 août 2013 à 16:01
Bonjour à tous,

je suis débutant en C++ et j'essaie actuellement de porter dans ce langage un programme que j'ai déjà créé en VB grâce à Qt. Ce programme permet de trouver des mots à partir de lettres en ajoutant des détails (vous pouvez voir plus de détails ici). J'ai donc créé un projet Qt, créé une fenêtre et écrit différents trucs, notamment une classe contenant un énorme dictionnaire. Celui ci doit être lors de l'initialisation de l'objet être mis dans un tableau (vector) puis être retourné à la classe qui a créé cet objet (qui récupère ainsi un tableau contenant le dictionnaire). L'intérêt est que le fichier est énorme, et donc fait planter sans arrêt Qt, ainsi en le mettant dans un objet à part que je ne modifie pas, je garde la stabilité de l'éditeur. Cependant j'obtiens cette erreur :

((dictionnaireIntegre*)this)->dictionnaireIntegre::dictionnaire' does not have class type
Mes fichiers :

main.cpp : http://pastebin.com/TJQj9t3E
fenetrePrincipale.cpp : http://pastebin.com/77JDL5tn
fenetrePrincipale.h : http://pastebin.com/Hp1n8Thn
dictionnaireintegre.cpp : http://thomaskowalski.net/fichiers/forums/lettrescpp/dictionnaireintegre.cpp
dictionnaireintegre.h : http://pastebin.com/BHUmKGF7

ou alors tout le projet : http://thomaskowalski.net/fichiers/forums/lettrescpp/fenetreprincipale.zip

Pourriez vous me dire ce qui ne va pas dans mon code ? A chaque problème j'ai trouvé un truc qui empêchait l'erreur mais là je ne vois pas..

Merci d'avance

Thomas

12 réponses

cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 123
Modifié par cptpingu le 6/08/2013 à 10:42
Bonjour.

Effectivement, écrire un tableau "en dur" dans ton code, c'est un peu du délire :p

Normalement, tu mets ton dictionnaire dans un fichier texte que tu charges au démarrage. De plus, comme tu retournes ton tableau par copie et non par référence, tu renvois une copie du tableau ! Je ne te dis pas la taille de gaché...
Enfin, si tu as besoin d'un dictionnaire, on ne fait pas un tableau, mais un arbre (std::map) ou une hash-map (std::unordered_map) dont les accès sont plus rapide pour ce genre de problématique: O(log(n) pour la std::map et O(1) pour la hash-map contre O(n) pour un tableau).
Ca dépend vraiment de ce que tu veux faire, mais d'une manière générale un dictionnaire se fait rarement avec un tableau.

Je ferais ceci (attention de tête, non testé), si tu veux conserver un tableau (pas la meilleur solution du tout):

#include <vector>
#include <iostream>

class Dico
{
   public:
     Dico();
     ~Dico();

    bool load(const std::string& filename);
    const std::string& operator[](int i) const;
    int size() const;

  private:
    std::vector<std::string> _dico;
};

Dico::Dico()
{
}

Dico::~Dico()
{
}

bool
Dico::load(const std::string& filename)
{
   std::ifstream file(filename.c_str());
   if (!file)
    return false;

  std::string line;
  while (std::getline(file, line))
    _dico.push_back(line);

  return true;
}

const std::string&
Dico::operator[](int i) const
{
  return _dico[i];
}

int
Dico::size() const
{
  return _dico.size();
}

int main()
{
  std::string filename = "dico.txt";
  Dico dico;
  if (!dico.load(filename))
  {
    std::cerr << "Error while loading dictionnary: " << filename << std::endl;
  }

  const int size = dico.size();
  for (int i = 0; i < size; ++i)
    std::cout << "dico[" << i << "] = " << dico[i] << std::endl;

  return 0;
}
1
Pouknouki Messages postés 45 Date d'inscription jeudi 21 juillet 2011 Statut Membre Dernière intervention 27 août 2014 6
6 août 2013 à 10:07
Merci beaucoup je vais voir ça et te dire si ça marche (parce qu'avec le dictionnaire en dur j'ai un Out of memory à la compilation ^^
1
Pouknouki Messages postés 45 Date d'inscription jeudi 21 juillet 2011 Statut Membre Dernière intervention 27 août 2014 6
6 août 2013 à 10:21
Bon, j'ai arrangé ce qui n'allait pas, mais maintenant on me fait une erreur dans le load() :
no match for 'operator>>' (operand types are 'std::ofstream {aka std::basic_ofstream<char>}' and 'std::string {aka std::basic_string<char>}')

Le projet entier est disponible à l'adresse thomaskowalski.net/fichiers/forums/fenetreprincipale.zip
Merci encore
1
cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 123
Modifié par cptpingu le 6/08/2013 à 10:48
Change le std::ofstream en std::ifstream, et ça devrait le faire. Tu peux aussi changer le "while (file >> line)" en "while (std::getline(file, line))", ce qui te permettra d'avoir des "mots coupés" en entier et pas seulement une partie. Ex: "Le chien" avec "file >> line" tu récupères "Le" et avec "getline", tu récupères "Le chien".

Que cherche-tu à faire ? La solution proposée est certe fonctionnelle, mais pas la meilleure du tout. Si tu expliquais la finalité de ton idée, je pourrais peut être t'aiguiller sur une solution plus adaptée.
1

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Pouknouki Messages postés 45 Date d'inscription jeudi 21 juillet 2011 Statut Membre Dernière intervention 27 août 2014 6
6 août 2013 à 10:49
Je cherche juste à avoir un tableau rempli de mots que je parcourrai ensuite pour effectuer des tests sur eux.
1
cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 123
6 août 2013 à 10:52
Par finalité, j'entendais ce que tu veux faire à terme.

Ex:
"Remplir un tableau" n'est pas une finalité, c'est un moyen.
"Réaliser une complétion en fonction des mots tapés" c'est une finalité.

Je te demande ça, car les algorithmes et structures de données vont complètement changer, en fonction de ce que tu veux réaliser.
1
Pouknouki Messages postés 45 Date d'inscription jeudi 21 juillet 2011 Statut Membre Dernière intervention 27 août 2014 6
6 août 2013 à 11:02
En fait je peux difficilement tout t'expliquer dans le topic, si tu veux bien comprendre lis mon article de bog:
http://thomaskowalski.net/programme-lettres/
1
cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 123
Modifié par cptpingu le 6/08/2013 à 15:51
Effectivement, à la lecture de ton article c'est bien plus clair.

La meilleure solution est celle-ci:
Tu associes une clé avec une valeur (hash map, donc une std::map ou mieux encore une std::unordered_map). Ta clé contient un std::string dont les lettres sont triées, et tu l'associes à un tableau de std::string.
Pour le premier cas, il suffit de chercher un mot "cochon", et la liste associée est retournée immédiatemment.
Pour le deuxième cas, vu que les lettres sont triées, il suffit de rechercher toutes les associations "d'une lettre" jusqu'à "size lettres".

J'ai réalisé ceci pour illustrer mes dires (fait en C++11, donc il faut ajouter l'option -std=c++0x pour que cela fonctionne, je peux te le convertir en C++ classique, si nécessaire).

Utils.hh
#ifndef UTILS_HH_
# define UTILS_HH_

# include <string>

namespace Utils
{
  std::string renarrow(const std::string& s);
  std::string cleanAndSort(const std::string& word);
} // Utils

#endif /* !UTILS_HH_ */


Utils.cc
#include "Utils.hh"
#include <sstream>
#include <algorithm>

namespace Utils
{
  std::string renarrow(const std::string& s)
  {
    std::ostringstream ws;
    unsigned int length = s.length();
    for (unsigned int i = 0; i < length; i++)
    {
      if (i + 1 < length && s[i] == -61)
      {
	switch (s[i + 1])
	{
	  case -94: ws << "a"; break;
	  case -96: ws << "a"; break;
	  case -89: ws << "c"; break;
	  case -85: ws << "e"; break;
	  case -87: ws << "e"; break;
	  case -86: ws << "e"; break;
	  case -88: ws << "e"; break;
	  case -81: ws << "i"; break;
	  case -82: ws << "i"; break;
	  case -76: ws << "o"; break;
	  case -69: ws << "u"; break;
	  case -71: ws << "u"; break;
	}
	i++;
      }
      else
      {
	switch (s[i])
	{
	  case -30: ws << "a"; break;
	  case -28: ws << "a"; break;
	  case -32: ws << "a"; break;
	  case -25: ws << "c"; break;
	  case -21: ws << "e"; break;
	  case -23: ws << "e"; break;
	  case -22: ws << "e"; break;
	  case -24: ws << "e"; break;
	  case -17: ws << "i"; break;
	  case -18: ws << "i"; break;
	  case -12: ws << "o"; break;
	  case -5: ws << "u"; break;
	  case -7: ws << "u"; break;
	  default : ws << s[i];
	}
      }
    }

    return ws.str();
  }

  std::string cleanAndSort(const std::string& word)
  {
    std::string res = renarrow(word);
    std::sort(res.begin(), res.end());
    return res;
  }
} // Utils


Combinations.hh
#ifndef COMBINATION_HH_
# define COMBINATION_HH_

# include <string>
# include <cassert>
# include <sstream>
# include <vector>
# include <stdint.h>

class Combinations
{
public:
  typedef std::vector<uint32_t> combination_type;

  Combinations(uint32_t maxIndex, uint32_t width);
  combination_type next();
  bool completed() const;
  bool generated() const;

private:
  bool             _completed;
  uint32_t         _generated;
  uint32_t         _maxIndex;
  int32_t          _width;
  combination_type _curr;
};

#endif /* !COMBINATION_HH_ */


Combinations.cc
#include "Combinations.hh"

Combinations::Combinations(uint32_t maxIndex, uint32_t width)
  : _completed(maxIndex < 1 || width > maxIndex),
    _generated(false),
    _maxIndex(maxIndex),
    _width(width)
{
  for (uint32_t c = 1; c <= width; ++c)
    _curr.push_back(c);
}

Combinations::combination_type
Combinations::next()
{
  combination_type ret = _curr;
  _completed = true;
  for (int32_t i = _width - 1; i >= 0; --i)
  {
    if (_curr[i] < _maxIndex - _width + i + 1)
    {
      uint32_t j = _curr[i] + 1;
      while (i <= _width)
	_curr[i++] = j++;
      _completed = false;
      ++_generated;
      break;
    }
  }

  return ret;
}

bool
Combinations::completed() const
{
  return _completed;
}

bool
Combinations::generated() const
{
  return _generated;
}



Dico.hh
#ifndef DICO_HH_
# define DICO_HH_

# include <string>
# include <iostream>
# include <unordered_map>
# include <vector>
# include <stdint.h>

class Dico
{
public:
  typedef std::vector<std::string> Words;
  typedef std::unordered_map<std::string, Words*> DicoType;
  typedef DicoType::iterator iterator;
  typedef DicoType::const_iterator const_iterator;

public:
  Dico();
  ~Dico();

  bool load(const std::string& filename);
  bool getListFromStrictLetters(std::string letters, Dico::Words*& list) const;
  bool getListFromPartialLetters(std::string letters, std::vector<Dico::Words*>& list, uint32_t width) const;
  void dump(std::ostream& out) const;

private:
  void add(const std::string& letters);

private:
  DicoType _dico;
};

std::ostream& operator<<(std::ostream& out, const Dico& dico);

#endif /* !DICO_HH_ */



Dico.cc
#include "Dico.hh"
#include "Utils.hh"
#include "Combinations.hh"

#include <fstream>
#include <cassert>
#include <sstream>
#include <iostream>

namespace
{
  void generateGroupPermutation(const std::string& word, uint32_t width,
				std::vector<std::string>& tab)
  {
    uint32_t size = word.size();

    Combinations cs(size, width);
    while (!cs.completed())
    {
      Combinations::combination_type c = cs.next();
      std::ostringstream buff;
      auto end = c.cend();
      for (auto it = c.cbegin(); it != end; ++it)
	buff << word[*it - 1];
      tab.push_back(buff.str());
    }
  }
} // namespace

Dico::Dico()
{
}

Dico::~Dico()
{
  auto end = _dico.end();
  for (auto it = _dico.begin(); it != end; ++it)
    delete it->second;
}

bool
Dico::getListFromStrictLetters(std::string letters, Dico::Words*& list) const
{
  const std::string word = Utils::cleanAndSort(letters);
  auto found = _dico.find(word);
  if (found == _dico.cend())
    return false;

  list = found->second;
  return true;
}

bool
Dico::getListFromPartialLetters(std::string letters, std::vector<Dico::Words*>& list, uint32_t width) const
{
  Dico::Words* words = 0;
  const std::string word = Utils::cleanAndSort(letters);
  uint32_t size = word.size();
  if (size < width)
    width = size;

  std::vector<std::string> tab;
  generateGroupPermutation(letters, width, tab);
  for (auto it = tab.begin(); it != tab.end(); ++it)
    if (getListFromStrictLetters(*it, words))
      list.push_back(words);

  return !list.empty();
}

bool
Dico::load(const std::string& filename)
{
  std::ifstream file(filename.c_str());
  if (!file)
    return false;

  std::string line;
  while (std::getline(file, line))
    add(line);

  return true;
}

void
Dico::add(const std::string& letters)
{
  const std::string word = Utils::cleanAndSort(letters);
  auto found = _dico.find(word);
  if (found == _dico.cend())
  {
    auto pair = _dico.insert(DicoType::value_type(word, new Dico::Words));
    if (!pair.second)
      return;
    found = pair.first;
  }
  found->second->push_back(letters);
}

void
Dico::dump(std::ostream& out) const
{
  auto end = _dico.cend();
  for (auto it = _dico.cbegin(); it != end; ++it)
  {
    out << "[" << it->first << "]: ";
    uint32_t i = 0;
    bool first = true;
    auto vec_end = it->second->cend();
    for (auto vec = it->second->cbegin(); vec != vec_end; ++vec, ++i)
    {
      if (first)
	first = false;
      else
	out << ", ";
      out << *vec;
    }
    out << std::endl;
  }
}

std::ostream& operator<<(std::ostream& out, const Dico& dico)
{
  dico.dump(out);
  return out;
}


main.cc
#include "Utils.hh"
#include "Dico.hh"

#include <iostream>

int main()
{
  std::string filename = "dico.txt";
  Dico dico;
  if (!dico.load(filename))
  {
    std::cerr << "Error while loading dictionnary: " << filename << std::endl;
    return 1;
  }

  //std::cout << "Dico:\n" << dico << std::endl;

  Dico::Words* words = 0;
  if (dico.getListFromStrictLetters("cone", words))
  {
    for (auto it = words->cbegin(); it != words->cend(); ++it)
      std::cout << " " << *it;
    std::cout << std::endl;
  }

  std::vector<Dico::Words*> list;
  if (dico.getListFromPartialLetters("enexppcottvj", list, 4))
  {
    for (auto vec = list.cbegin(); vec != list.cend(); ++vec)
      for (auto it = (*vec)->cbegin(); it != (*vec)->cend(); ++it)
	std::cout << " " << *it;
    std::cout << std::endl;
  }
  else
    std::cout << " not found!" << std::endl;

  return 0;
}
1
Pouknouki Messages postés 45 Date d'inscription jeudi 21 juillet 2011 Statut Membre Dernière intervention 27 août 2014 6
6 août 2013 à 13:03
Merci je vais voir ça. Mais en fait le but du sujet n'était pas que quelqu'un le fasse à ma place mais que je le fasse moi même en apprenant à résoudre mes problèmes. Et maintenant j'en suis à vérifier que le dictionnaire est rempli, je fais
boutonRechercher->setText(Dictionnaire[4].c_str());

Et l'application crash...
1
cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 123
6 août 2013 à 13:30
Je ne te fais pas le travail, dans le sens où tu as déjà réalisé celui-ci (je ne poste jamais de code sans m'être assuré que le demandeur soit sérieux, et ton article était suffisamment complet pour me laisser penser que tu avais déjà fait toutes les démarches de codes et de réflexions). Je te présente simplement une solution plus élaborée. Libre à toi de l'étudier ensuite.

Pour ton souci, vérifie que 4 n'est pas hors borne via ".size()".
1
Pouknouki Messages postés 45 Date d'inscription jeudi 21 juillet 2011 Statut Membre Dernière intervention 27 août 2014 6
6 août 2013 à 13:54
D'accord je comprends ton raisonnement.
J'ai vérifié la taille du tableau, il fait bien pile la taille du nombre de lignes dans le fichier, et on peut bien accéder aux différentes "cases". Je vais faire des tests et voir ce que ça donne.
1
cptpingu Messages postés 3837 Date d'inscription dimanche 12 décembre 2004 Statut Modérateur Dernière intervention 28 mars 2023 123
Modifié par cptpingu le 6/08/2013 à 16:02
Au cas où ça t'interesserait (pour plus tard), j'ai corrigé mon code qui ne fonctionnait pas (cf mon post que j'ai édité: http://codes-sources.commentcamarche.net/forum/affich-10002061-erreurs-par-milliers-qt#p10002149 ).
La technique dont je t'ai parlé est performante:
- Il me faut 0.7 secondes pour charger entièrement le fichier dans la classe dictionnaire.
- Pour rechercher tous les anagrammes de "cone" il me faut 43 micro-secondes (3 résultats retournés).
- Pour rechercher tous les mots de 4 lettres sachant qu'on a des lettres en trop pour le mot "enexppcottvj", il me faut 895 micro-secondes (159 résultats).

Pas besoin de barre de progression :p
1
Rejoignez-nous