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 :

Mon programme c++ crash juste apres une requête SQLite


Sujet :

C++

  1. #1
    Membre confirmé Avatar de humitake
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2010
    Messages
    399
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2010
    Messages : 399
    Points : 578
    Points
    578
    Par défaut Mon programme c++ crash juste apres une requête SQLite
    Bonjour,

    Depuis hier lorsque j'exécute mon programme je me retrouve face à un message d'erreur Windows disant que mon programme a cessé de fonctionner. L'erreur survient juste après une requête, lorsque j'exécute la méthode createTables() cette dernière exécute une requête (création de la table Plans) puis crash. Je n'ai donc pas accès aux message d'erreur car il se produit au moment de l'exécution.

    Si quelqu'un peut m'indiquer d'où viens ce problème ...
    Merci d'avance !

    Fichier BD.h
    Code c++ : 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
    #ifndef BD_H_
    #define BD_H_
     
    #include "sqlite3.h"
    #include <stdlib.h>
    #include <iostream>
     
    class BD {
    private:
    	sqlite3 *connection;
    	char** erreurBD;
    	char* sql;
    public:
    	BD();
    	virtual ~BD();
    	sqlite3* getConnection();
    	int query();
    	int createTables();
    	int dropTables();
    };
     
    #endif /* BD_H_ */

    Fichier BD.cpp
    Code c++ : 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
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    #include "BD.h"
    using namespace std;
     
    /*
     * Constructeur par defaut
     */
    BD::BD(){
    	sqlite3_open("fireScan.sqlite", &this->connection); //Permet de créer la connexion à la base de données
    }
     
    /*
     * Destructeur
     */
    BD::~BD(){
    	sqlite3_close(connection);
    }
     
    /*
     * Accesseur à la connexion
     * @return sqlite3* connection : la connexion à la base de données
     */
    sqlite3* BD::getConnection(){
    	return connection;
    }
     
    /*
     * Méthode permetant d'exécuter une requête
     * @return int : 0 en cas de réussite, -1 sinon
     */
    int BD::query(){
    	cout << sql << endl;
    	int rc = sqlite3_exec(connection, sql, NULL, NULL, erreurBD);
    	if( rc!=SQLITE_OK ){
    		cout << "Erreur dans la requête";
    		return -1;
    	}
    	return 0;
    }
     
    /*
     * Methode permetant de créer la structure de la base de données
     * @return int : 0 en cas de réussite, -1 sinon
     */
    int BD::createTables(){
    	sql = "CREATE TABLE Plans(idPlan INTEGER PRIMARY KEY, libPlan VARCHAR(40), urlPlan VARCHAR(100))";
    	query();
     
    	sql = "CREATE TABLE Zones(idZone INTEGER PRIMARY KEY, libZone VARCHAR(40), idPlan INTERGER, FOREIGN KEY(idPlan) REFERENCES Plans(idPlan))";
    	query();
     
    	return 0;
    }
     
    /*
     * Méthode permetant de supprimer la structure et les données de la base
     * @return int : 0 en cas de réussite, -1 sinon
     */
    int BD::dropTables(){
    	sql = "DROP TABLE Plans";
    	query();
     
    	sql = "DROP TABLE Zones";
    	query();
     
    	return 0;
    }

    Fichier main.cpp
    Code c++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #include "BD/BD.h"
    #include <iostream>
    #include <windows.h>
    using namespace std;
     
    int main(int argc, char* argv[]){
    	BD *bd = new BD();
    	bd->dropTables();
    	bd->createTable();
    	delete bd;
    }

  2. #2
    Membre émérite
    Avatar de Daïmanu
    Homme Profil pro
    Développeur touche à tout
    Inscrit en
    Janvier 2011
    Messages
    696
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur touche à tout

    Informations forums :
    Inscription : Janvier 2011
    Messages : 696
    Points : 2 440
    Points
    2 440
    Par défaut
    Salut.

    Citation Envoyé par humitake Voir le message
    CREATE TABLE Zones(idZone INTEGER PRIMARY KEY, libZone VARCHAR(40), idPlan INTERGER, FOREIGN KEY(idPlan) REFERENCES Plans(idPlan))
    Erreur dans la requête (INTERGER).

    Essaie avec INTEGER.
    Je fais appel aux esprits de Ritchie, Kernighan, Stroustrup et Alexandrescu
    Donnez moi la force, donnez moi le courage de coder proprement !

    « Ça marche pas » n'est PAS une réponse convenable, merci de détailler le souci en fournissant l’environnement, le code source, les commandes et les messages d'erreur.

    Ce club possède également un clavardage, on y trouve quelques perles entre deux sessions d'entraides.

  3. #3
    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
    Bonjour,
    Je ne connais pas SQL Lite mais quelques remarques sur ton code :

    sqlite3_exec(connection, sql, NULL, NULL, erreurBD); : C'est QSLite qui se charge d'allouer la chaîne de caractère (empoussiérée de C) et de te retourner l'adresse dans le dernier paramètre. Tu dois donc lui donner un espace où entrer cette adresse. Toi tu lui donne une adresse sur un espace non alloué. Donc quand il écrit dedans il écrit à une zone invalide participant à l'erreur que tu observe. Il faut déclarer erreurBD comme un pointeur de char et donner l'adresse de cette variable lors de l'appel :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    class BD {
    private:
    	char* erreurBD;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    int rc = sqlite3_exec(connection, sql.c_str(), NULL, NULL, &erreurBD);
    Qui plus est, tu dois libérer cette chaine ensuite avec sqlite3_free.

    Chaque fichier (surtout les fichiers d'en-têtes) ne doivent contenir que les directives d'inclusion dont ils ont réellement besoin (F.A.Q Quels fichiers d'en-tête dois-je inclure ?). BD.h n'a ni besoin de iostream ni besoin de stdlib.h. Il faut les sortir et ne les mettre dans le .cpp que si réellement besoin

    les en-têtes issu du C en C++ se préfixe par 'c' et n'ont plus de .h : cstdlib.

    Ta class BDgérant une ressource devrait avoir une politique de copie maîtrisée (tutoriel : Gérer ses ressources de manière robuste en C++ et F.A.Q : Sémantique de copie ). Le mieux ici est probablement de la rendre non copiable.

    Les chaînes de caractères en C++ ont leur type : std::string (F.A.Q Les chaînes de caractères). Autant en profiter, cela sera moins hasardeux que d'utiliser des pointeurs sur char en dur vers des littéraux.

    std:: n'a pas trop tendance à user le clavier ni les doigts. On peut donc assez facilement se passer des using namespace (F.A.Q. Quand utiliser / ne pas utiliser using namespace ?).

    Pourquoi faire un new dans main ? Java/C# ont déteints ?

    Tu devrais initialiser les éléments de ta classe dans la liste d'initialisation du constructeur pour ne pas les laisser dans un état indéterminé.

    Au final ton code pourrait ressembler à :

    Code bd.h : 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
    #ifndef BD_H_
    #define BD_H_
    #include <string>
    struct sqlite3;
     
    class BD {
    private:
    	sqlite3 *connection;
    	char* erreurBD;
    	std::string sql;
     
    	// non copiable :
    	BD(BD const&); // = delete;
    	BD&operator=(BD const&); // = delete
    public:
    	BD();
    	virtual ~BD();
    	sqlite3* getConnection();
    	int query();
    	int createTables();
    	int dropTables();
    };
    #endif /* BD_H_ */

    Code bd.cpp : 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
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    #include "bd.h"
    #include "sqlite3.h"
    #include <iostream>
     
    /*
     * Constructeur par defaut
     */
    BD::BD()
    :connection(0),erreurBD(0)
    {
    	sqlite3_open("fireScan.sqlite", &this->connection); //Permet de créer la connexion à la base de données
    }
     
    /*
     * Destructeur
     */
    BD::~BD(){
    	sqlite3_close(connection);
    }
     
    /*
     * Accesseur à la connexion
     * @return sqlite3* connection : la connexion à la base de données
     */
    sqlite3* BD::getConnection(){
    	return connection;
    }
     
    /*
     * Méthode permetant d'exécuter une requête
     * @return int : 0 en cas de réussite, -1 sinon
     */
    int BD::query(){
    	std::cout << sql << std::endl;
       int rc = sqlite3_exec(connection, sql.c_str(), NULL, NULL, &erreurBD);
    	if( rc!=SQLITE_OK ){
    		std::cout << "Erreur dans la requête\n";
    		if(0!=erreurBD)
    		{
    			sqlite3_free(erreurBD);
    			erreurBD=0;
    		}
    		return -1;
    	}
    	return 0;
    }

    Code main.cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    int main(){
    	BD bd;
    	bd.dropTables();
    	bd.createTables();
    	return 0;
    }

  4. #4
    Membre expert
    Avatar de Klaim
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2004
    Messages
    1 717
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 717
    Points : 3 344
    Points
    3 344
    Par défaut
    Conseil pour te simplifier la vie : utilise un wrapper C++ autour de SQLite, ça t'évitera de tomber dans les problèmes d'allocation.

    Il y en a plusieurs de dispo sur le wiki du site de sqlite.

  5. #5
    Membre confirmé Avatar de humitake
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2010
    Messages
    399
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2010
    Messages : 399
    Points : 578
    Points
    578
    Par défaut
    Merci pour le coup d’œil manudiclemente

    Citation Envoyé par 3DArchi
    Chaque fichier (surtout les fichiers d'en-têtes) ne doivent contenir que les directives d'inclusion dont ils ont réellement besoin (F.A.Q Quels fichiers d'en-tête dois-je inclure ?). BD.h n'a ni besoin de iostream ni besoin de stdlib.h. Il faut les sortir et ne les mettre dans le .cpp que si réellement besoin
    Je me permet de te demander l’intérêt d'une telle chose (ce n'est pas décrit dans la FAQ). On ne m'a jamais expliqué cela, ou alors je m'étais assoupie, du coup je trouvais sa plus "organiser" de placer tous les includes dans un seul et même fichier

    Citation Envoyé par 3DArchi
    Pourquoi faire un new dans main ? Java/C# ont déteints ?
    Oui effectivement mes habitudes de Java ont la vie dur

    Citation Envoyé par 3DArchi
    Les chaînes de caractères en C++ ont leur type : std::string (F.A.Q Les chaînes de caractères). Autant en profiter, cela sera moins hasardeux que d'utiliser des pointeurs sur char en dur vers des littéraux.
    Oui je les utilisent dès que je peux, malheureusement je me trouve souvent confronté à des problèmes de compatibilité (demande un const char*) et souvent directement le type de ma chaine...

    Citation Envoyé par 3DArchi
    std:: n'a pas trop tendance à user le clavier ni les doigts. On peut donc assez facilement se passer des using namespace (F.A.Q. Quand utiliser / ne pas utiliser using namespace ?).
    Si l'on peut s'en passer à quoi sert le using namespace ? Gagne t'on en temps de compilation si l'on s'en passe ?

    Je te remercie également pour le coup de la copie que je ne connaissais pas du tout

    [Edit:] Merci Klaim effectivement je vais me pencher un peux sur ces wrapper

  6. #6
    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
    Citation Envoyé par humitake Voir le message
    Je me permet de te demander l’intérêt d'une telle chose (ce n'est pas décrit dans la FAQ). On ne m'a jamais expliqué cela, ou alors je m'étais assoupie, du coup je trouvais sa plus "organiser" de placer tous les includes dans un seul et même fichier
    C'est une question de qualité de code avec les objectifs suivants :
    • Identifier rapidement les dépendances entre les fichiers (savoir qui a réellement besoin de qui). Ça aide grandement en maintenance.
    • Ne pas avoir d'interdépendances inutiles. Éviter l'effet spaghetti.
    • Ne pas injecter des identifiants inutiles (A.h inclus B.h qui inclus C.h : A a-t-il besoin des symboles définis dans C ?)
    • Accessoirement, ça accélère les compilations
    • ...



    Citation Envoyé par humitake Voir le message
    Oui je les utilisent dès que je peux, malheureusement je me trouve souvent confronté à des problèmes de compatibilité (demande un const char*) et souvent directement le type de ma chaine...
    Utilise c_str() là où une interface C demande un [codeiline]const char*[/codeinline].

    Citation Envoyé par humitake Voir le message
    Si l'on peut s'en passer à quoi sert le using namespace ?
    A mon avis, à rien (enfin, pour de la compatibilité avec des codes préhistoriques fait avec Visual C++6 est la seule raison qui me viennent). Je préfère écrire l'espace de nom. Mais pour ceux que ça fatigue vraiement, je me demande si je ne préfère pas using std::cout;. Et pour les espaces de noms un peu trop long, je préfère les alias : namespace ma_lib = une_bibliotheque::vraiement::consomatrice::despace::de::noms;.

    Citation Envoyé par humitake Voir le message
    Gagne t'on en temps de compilation si l'on s'en passe ?
    Je ne sais pas. A priori, je dirais non, ou alors ce doit être négligeable.

    Sinon, tout à fait d'accord avec Klaim. Si tu as une interface pure C++ qui te masque toutes ces allocations, qui comprend des std::string, prends.

  7. #7
    Membre confirmé Avatar de humitake
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2010
    Messages
    399
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2010
    Messages : 399
    Points : 578
    Points
    578
    Par défaut
    Merci pour toutes ces précision !

    Sujet résolu

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [CS3] Mon programme ne fonctionne plus après une copie
    Par Jeffreyshep dans le forum Flash
    Réponses: 1
    Dernier message: 05/09/2014, 10h24
  2. Réponses: 17
    Dernier message: 15/04/2011, 01h08
  3. Etat après une requête
    Par platoon64 dans le forum Bases de données
    Réponses: 2
    Dernier message: 22/05/2006, 14h03
  4. [MySQL] Afficher une date correctement après une requête
    Par Nerva dans le forum PHP & Base de données
    Réponses: 5
    Dernier message: 12/04/2006, 16h27
  5. Réponses: 2
    Dernier message: 29/12/2005, 10h25

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