Je suis un peu perplexe par celui-ci. Tout va bien jusqu'à présent avec l'utilisation de Sqlite mais j'essaie maintenant de stocker mes résultats de la requête dans une structure simple. Lorsque je fais cela dans mon rappel, toutes mes données sont superbes dans mon vecteur Sqlitems, mais dès que le rappel sortit, mon vecteur Sqlitems tenant mes lignes de données est soudainement corrompu. Des idées ce qui pourrait causer cela?
// Simple struct to hold column name and row data
struct SQLrow {
char * Column;
char * Data;
};
// static Vector to hold SQL rows
static std::vector<SQLrow> SQLItems;
...
// static callback that handles placing query results into structs and into SQLItems vector
// SQLItems column/row data gets corrupted after this function exits
static int countTablesCallback(void *data, int count, char **rows, char **azColName) {
int i;
for (i = 0; i < count; i++) {
SQLrow newItem = { azColName[i] ,rows[i] };
SQLItems.push_back(newItem);
}
*static_cast<std::vector<SQLrow>*>(data) = SQLItems; // Tried this too but throws an exception
return 0;
}
3 Réponses :
Il suffit de regarder le code, il apparaît que les données pointées par Un moyen simple est de changer des lignes code> seront invalidées / détruites / modifiées une fois que le rappel retourne. Donc, vous ne pouvez pas conserver ces indications pour une utilisation ultérieure et devront effectuer une copie des données. P>
colonne code> et de données code> à partir de char * code> à std :: chaîne code>. À défaut, vous devrez faire une sorte de gestion de la mémoire manuelle (allouer de l'espace avec nouveau code>, puis la supprimer ultérieurement), qui est sujette d'erreur et pas vraiment souhaitable ces jours-ci. P>
Vous et @timo sont corrects. Juste hors de curiosité, comment se passera-t-il en utilisant des types de données Char * au lieu de STD :: String? Avez-vous un exemple de cela quelque part que je peux envelopper ma tête?
Ajouter un constructeur à Sqlrow qui prend deux td :: String comme: SQLROW (STD :: String Colonne, STD :: String Data): colonne (colonne), données (données) {}.
Ensuite, utilisez-le en construisant les deux cordes d'abord comme ceci: STD :: String c (azcolname [I]); std :: string d (rangées [i]); , puis pour construire votre sqlrow comme ceci: Sqlrow Row (C, D); Puis poussez-le.
@Antonio j'aime votre suggestion mais je voulais dire comment j'irais éventuellement à faire cela sans utiliser STD :: String Types?
@DRWBNS Si vous ne voulez pas utiliser std :: string code> et sa gestion automatique de la mémoire, vous devrez attribuer manuellement l'espace pour les données. Quelque chose comme nouveau char [SHLEN (lignes [i]) + 1] code>, copiez les données dans, rappelez-vous d'appeler Suppr [] Données CODE> lorsque vous avez terminé avec elle . Beaucoup de façons simples de gâcher cela et, comme je l'ai dit dans ma réponse, pas conseillé ces jours-ci.
@ 1201ProgrammAlarm a eu! Merci pour l'entrée!
Votre vecteur va bien, le static_cast (code> n'a aucun sens là-bas, sauf si DATA code> est réellement utilisé comme paramètre OUT. Votre problème est, très probablement, que sqlrow code> contient le pointeur de caractère et SQLite supprime les chaînes pointées après le retour du rappel. Changer votre classe sur struct SQLrow {
std::string Column;
std::string Data;
};
À mon avis, il y a très peu de cas dans lesquels vous voulez / besoin d'utiliser une chaîne brute en C ++ et que vous n'êtes pas l'un de ceux-ci. Au fait, j'espère que cela vous aidera ou quelqu'un d'autre d'une manière ou d'une autre:
#include <vector>
#include <stdio.h>
#include <string.h>
#include <iostream>
struct SQLrow {
char* Column;
char* Data;
};
void your_callback(int count, char **rows, char **azColName) {
std::vector<SQLrow> rows_list;
for (int i = 0; i < count; i++) {
/* Uncomment this if you want
your copy of the strings. If you
use this, don't forget to free the
memory yourself with delete[] s1 and
s2.
size_t s1_len = strlen(rows[i]);
size_t s2_len = strlen(azColName[i]);
char* s1 = new char [sizeof(char) * (s1_len + 1)];
char* s2 = new char [sizeof(char) * (s2_len + 1)];
memcpy(s1, rows[i], s1_len);
s1[s1_len] = '\0';
memcpy(s2, azColName[i], s2_len);
s2[s2_len] = '\0';
SQLrow r = { s1, s2 }; */
SQLrow r = { rows[i], azColName[i] };
rows_list.push_back(r);
}
// test the result
for (int i = 0; i < count; i++) {
SQLrow r = rows_list.at(i);
std::cout << "rows:" << r.Column << " azColName:" << r.Data << std::endl;
}
}
// this 2 lines are just for simulating the data
// you will get this 'warning: ISO C++ forbids converting a string constant to char*''
char* rows[] = {"row1", "row2" , "row3" };
char* colName[] = {"name1", "name2", "name3" };
int main()
{
your_callback(3, rows, colName);
return 0;
}
Si vous souhaitez accéder aux résultats d'une sélection, n'utilisez pas cette interface de rappel avec
sqlite3_exec () code>. Utilisez un Préparation préparée dans une boucle. Beaucoup plus facile à travailler avec.