highscore only refreshing on launch sqlite - c++

I have a highscore system implemented using SQLite for a c++ shooter ive made but it only refreshes when I relaunch the game, I think this is because it only re- sorts from largest to smallest on game launch. I don't know why this is, it does seem to record all game scores as it should, but I think it is only ordering them on launch. How could I make it so it re-orders before it prints to screen. Here is the code
in main.cpp
case eHIGH_SCORES:
DrawString( "HIGHSCORES", iScreenWidth * 0.38, iScreenHeight * 0.95);
DrawString( "PRESS C TO CLOSE", iScreenWidth * 0.32, iScreenHeight * 0.1);
DatabaseMaker DatabaseMaker("MyDatabase.db");
DatabaseMaker.CreateDatabase();
DatabaseMaker.CreateTable("HIGHSCOREST");
if (scorer<1)
{
DatabaseMaker.InsertRecordIntoTable("HIGHSCOREST",scoreArray);
scorer++;
for (int i=0; i<10; i++)
{
scoreArray[i]=0;
}
}
DatabaseMaker.RetrieveRecordsFromTable("HIGHSCOREST");
DatabaseMaker.databaseprinter();
then in the Database maker class I have
DatabaseMaker::DatabaseMaker(std::string HighScoresT)
{
this->HighScores = HighScoresT;
myDatabase = NULL;
}
int DatabaseMaker::Callback(void* notUsed, int numRows, char **data, char **columnName)
{
for(int i = 0; i < numRows; i++)
{
std::cout << columnName[i] << ": " << data[i] << std::endl;
holder.push_back(atoi(data[i]));
}
return 0;
}
void DatabaseMaker::databaseprinter()
{
for (int i = 0; i < 10; i++)
{
itoa(holder[i], displayHolder, 10);
DrawString(displayHolder, 780/2, 700-(50*i));
}
}
void DatabaseMaker::CreateDatabase()
{
int errorCode = sqlite3_open(HighScores.c_str(), &myDatabase);
if(errorCode == SQLITE_OK)
{
std::cout << "Database opened successfully." << std::endl;
}
else
{
std::cout << "An error has occured." << std::endl;
}
}
void DatabaseMaker::CreateTable(std::string HIGHSCOREST)
{
char* errorMsg = NULL;
std::string sqlStatement;
sqlStatement = "CREATE TABLE HIGHSCOREST(" \
"ID INT," \
"SCORE INT);";
sqlite3_exec(myDatabase, sqlStatement.c_str(), Callback, 0, &errorMsg);
if(errorMsg != NULL)
{
std::cout << "Error message: " << errorMsg << std::endl;
}
}
void DatabaseMaker::InsertRecordIntoTable(std::string HIGHSCOREST,int (&scoreArray)[10] )
{
char*errorMsg = NULL;
std::string sqlStatement;
int x=5;
for(int i=0;i<10;i++)
{
std::string scorestring;
scorestring = std::to_string(scoreArray[i]);
sqlStatement = "INSERT INTO HIGHSCOREST (ID,SCORE)" \
"VALUES (1,"+scorestring+");";
sqlite3_exec(myDatabase, sqlStatement.c_str(), Callback, 0, &errorMsg);
if(errorMsg != NULL)
{
std::cout << "Error message: " << errorMsg << std::endl;
}
}
}
void DatabaseMaker::RetrieveRecordsFromTable(std::string HIGHSCOREST)
{
char* errorMsg = NULL;
std::string sqlStatement;
sqlStatement = "SELECT SCORE from HIGHSCOREST order by SCORE desc;";
sqlite3_exec(myDatabase, sqlStatement.c_str(), Callback, 0, &errorMsg);
if(errorMsg != NULL)
{
std::cout << "Error message: " << errorMsg << std::endl;
}
sqlite3_close(myDatabase);
}
DatabaseMaker::~DatabaseMaker()
{
}

Well, maybe try to move sqlite3_close statement off the RetrieveRecordsFromTable member function, maybe to destructor or seperate function?
Since you close connection to database after calling it for first time (and this might be a reason the problem is fixed by rerunning your application).
Also, consider changing this DatabaseMaker DatabaseMaker("MyDatabase.db"); into this: DatabaseMaker databaseMaker("MyDatabase.db");, otherwise you might have problem defining another DatabaseMaker in same scope.

Related

hiredis messages not arriving in subscribed handler

I have been working with hiredis as a client, everything e.g set, publish, etc works except for subscribe. I'm able to subscribe but can't get any message when I try to publish to the channel I've subscribed to. Here is the code I'm using:
int main() {
signal(SIGPIPE, sigHandler);
struct event_base *base = event_base_new();
assert(base != nullptr);
auto redis = redisAsyncConnect(IP, PORT);
if (redis != nullptr && redis->err) {
std::cerr << redis->err;
delete redis;
exit(1);
}
std::cout << "Connected" << END;
int flag;
std::cout << "Calling redisLibeventAttach" << END;
redisLibeventAttach(redis, base);
flag = redisAsyncCommand(redis, onMessage, (char *) "sub", "SUBSCRIBE test");
std::cout << "Command ret: " << flag << END;
flag = event_base_dispatch(base);
std::cout << " Event base flag " << flag << END;
return 0;
}
And the on message function:
void onMessage(redisAsyncContext *context, void *r, void *data) {
assert(r != nullptr);
auto *reply = static_cast<redisReply *>(r);
assert(reply != nullptr);
std::cout << "Reply " << reply->type << END;
switch (reply->type) {
case REDIS_REPLY_ARRAY:
for (int i = 0; i < reply->elements; ++i) {
std::cout << i << " -- " << reply->element[i]->str << END;
}
break;
case REDIS_REPLY_STRING:
std::cout << reply->str << END;
break;
}
}
Is there anything else I'm supposed to do?

Passing a variable through signal and slot system in Qt [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
So I want to pass a std::string variable through the signal and slot system in Qt; I have a class on heap called RecordTalks which emits a signal when received message from chat is longer than 25 signs.
The code is as follows:
#include "recordtalks.h"
// records chat to files RecordTalks::RecordTalks(QObject *parent) {
}
RecordTalks::~RecordTalks() {
std::cout << "destructor" << "\n"; }
void RecordTalks::run(QString data) {
std::cout << ">>> whole data is: " << data.toStdString() << " ------------------\n";
std::string text = data.toStdString();
extractNick(text);
extractRoom(text);
//std::cout << "save in recordTalks is: " << save << "\n";
if((nick.size()!=0 && room.size()!=0))
{
extractText(data);
pushToVector(removeDigitsAndSpecials(nick), subText);
}
else
return; }
void RecordTalks::run() {
save=false;
save = console.saveNowState();
if(save==true)
{
saveToFile(allTexts, "BOT"); //trigger line saving to file
file.close();
removeDuplicatedNicks();
createNickFiles(nicks_v);
match_nicks_and_allTexts(allTexts);
closeNickFiles();
nicks_v.clear();
nickAndFile_pair_vec.clear();
text.clear();
allTexts.clear();
nick.clear();
room.clear();
subText.clear();
save=false;
}
}
void RecordTalks::extractText(QString &data) {
std::string text = data.toStdString(); // tu zmiana
size_t pos, pos2;
if((pos=text.find("PRIVMSG #"))!=std::string::npos)
{
if((pos2=text.find(":",pos))!=std::string::npos)
{
subText = text.substr(pos2+1, text.size()-(pos2+1) );
if((pos=subText.find("\u0001ACTION "))!=std::string::npos)
{
subText = subText.substr(pos+8 , subText.size()-3-(pos+8));
}
else
std::cout << "subText: " << subText << "\n";
}
}
else //if nothing to write to log:
{
return ;
}
}
void RecordTalks::extractNick(std::string &text) {
Extract_NickAndRoom e;
QString temp = QString::fromStdString(text);
nick = e.extractNick(temp);
//std::cout << "nick is: " << nick << "\n";
}
void RecordTalks::extractRoom(std::string &text) {
Extract_NickAndRoom e;
QString temp = QString::fromStdString(text);
room = e.extractRoom(temp);
//std::cout << "room is: " << room << "\n"; }
void RecordTalks::pushToVector(std::string nick, std::string &subText)
//general vector with texts {
if(subText.size()>25 ) //if line of text from irc is bigger than 25 signs
{
std::pair<std::string, std::string> para = std::make_pair(nick, subText);
allTexts.push_back(para); // pair --> vector
emit textUpdateSignal(subText);
std::cout << "EMITTTTTTTTTTTTTTTTTTT " << "\n";
//std::cout << ">>> subText: " << subText << " nick: " << nick << " <<<" << "\n";
}
if(allTexts.size()==60)
{
saveToFile(allTexts, "BOT"); //trigger line saving to file
file.close();
removeDuplicatedNicks();
createNickFiles(nicks_v);
match_nicks_and_allTexts(allTexts);
closeNickFiles();
nicks_v.clear();
nickAndFile_pair_vec.clear();
text.clear();
allTexts.clear();
nick.clear();
room.clear();
subText.clear();
save=false;
}
}
void RecordTalks::saveToFile( std::vector< std::pair<std::string,
std::string> > &allTexts, std::string nickFileName) {
std::string address = "D:\\Qt_workspace\\weatherBot\\logs\\" + nickFileName + ".txt";
file.open(address, std::ios::out | std::ios::app);
for (int i = 0; i < allTexts.size(); ++i)
{
file << allTexts[i].second; //writes text to file, not the nicks
}
}
void RecordTalks::createNickFiles(std::vector<std::string> &nicks_v) {
/* make vector of pair nick and file, so we can identify the file name and then
put text-matching-to-file-nick with file name */
for (int i = 0; i < nicks_v.size(); ++i)
{
std::fstream file2("D:\\Qt_workspace\\weatherBot\\logs\\"+ nicks_v[i] + ".txt",
std::ios::out | std::ios::app);
std::pair<std::string, std::fstream> nickAndFile_pair;
nickAndFile_pair = std::make_pair(removeDigitsAndSpecials(nicks_v[i]),
std::move(file2));
nickAndFile_pair_vec.push_back(std::move(nickAndFile_pair));
}
}// nicks_v[i] put inside function removeDigitsAndSpecials(std::string& nick)
void RecordTalks::match_nicks_and_allTexts(std::vector<
std::pair<std::string, std::string> > allTexts) {
for (int i = 0; i < nickAndFile_pair_vec.size(); ++i)
{
for (int j = 0; j < allTexts.size(); ++j)
{
if(nickAndFile_pair_vec[i].first == allTexts[j].first)
{
nickAndFile_pair_vec[i].second << allTexts[j].second;
//nickAndFile_pair_vec[j].second.flush();
}
}
}
std::cout << "allTexts size in match_nicks_and_allTexts is: ";
std::cout << allTexts.size() << "\n";
}
void RecordTalks::removeDuplicatedNicks() {
std::vector< std::pair<std::string, std::string> > temp = allTexts;
std::cout << "temp size: " << temp.size() << "\n";
for (int i = 0; i < temp.size(); ++i)
{
for (int j = i+1; j < temp.size(); ++j)
{
if(temp[i].first == temp[j].first && i+1< temp.size())
{
temp.erase(temp.begin()+j);
j--;
}
}
}
for (int i = 0; i < temp.size(); ++i)
{
nicks_v.push_back(temp[i].first);
}
std::cout << "nicks_v.size: " << nicks_v.size() << "\n";
}
void RecordTalks::closeNickFiles() //closes separate nick files {
for (int i = 0; i < nickAndFile_pair_vec.size(); ++i)
{
nickAndFile_pair_vec[i].second.close();
}
std::cout << "Files closed..." << "\n"; }
std::string RecordTalks::removeDigitsAndSpecials(std::string& nick) {
for (int i = 0; i < nick.size(); ++i)
{
if(std::isalpha(nick[i]))
{
}
else if(std::isdigit(nick[i]))
{
nick.erase(nick.begin()+i);
std::cout << "removing: " << nick[i] << "\n";
i--;
}
else
{
nick.erase(nick.begin()+i);
std::cout << "removing: " << nick[i] << "\n";
i--;
}
}
return nick;
}
Then in another class i have the connect function. When i write it in this form:
connect(recordTalks, &RecordTalks::textUpdateSignal, this, &Socket::updateDatabaseSLOT);
the slot receives the signal. But when i write the function this way:
connect(recordTalks, SIGNAL(textUpdateSign(std::string)), this,
SLOT(updateDatabaseSLOT(std::string)));
the Slot is not fired. So my question is, what is the reason of that. In other cases the latter version works just fine.
The slot looks like this:
void Socket::updateDatabaseSLOT(std::string textUpdate)
{
std::cout << "updates text: << textUpdate << "\n";
database.push_back(textUpdate);
}
I think you have a typo in your connect statement. Qt can be frustrating that way. SIGNAL(textUpdateSign(std::string ) should probably be SIGNAL(textUpdateSignal(std::string ).

Write and Read method stop my execution - pipes c++

I'm just trying to make a "Tree" where I've a ctrsis and (for now) n "Children" connected to the ctrsis by pipes; But something happen when I try to pass data through pipes from childen to parent and parent to children using stdin and stdout, specificly when I use write() cpp function.
//ctrsis.cpp
int
main(void) {
vector<WriteIn> TubesReference;
WriteIn mainTube;
TubesReference.push_back(mainTube);
const char* file = "ctrsis.cfg";
int levelOneProcesses = 0;
string line;
ifstream configFile(file);
if(configFile.is_open()){
while ( getline (configFile,line) ){
WriteIn structure = createTube(line);
TubesReference.push_back(structure);
levelOneProcesses++;
}
}else{
cout << "Unable to open file" << endl;
}
configFile.close();
if ((TubesReference[0].in = open("ctrsis.cfg", O_RDONLY)) == -1) {
std::cerr << "Error open file" << std::endl;
return 1;
}
TubesReference[0].out = TubesReference[1].pipeOut[1];
for (int i = 1; i < levelOneProcesses; ++i){
TubesReference[i].in = TubesReference[i].pipeIn[0];
if(i != TubesReference.size()-1){
TubesReference[i].out = TubesReference[i+1].pipeOut[1];
}else{
TubesReference[TubesReference.size()-1].out = 1;
}
}
pthread_t levelOneThreads[levelOneProcesses];
for(int i = 0; i < levelOneProcesses; ++i){
vector<string> vec;
istringstream iss(TubesReference[i+1].line);
copy(istream_iterator<string>(iss),
istream_iterator<string>(),
back_inserter(vec));
string file = "FICHEROCFG=" + vec[4];
string folder = "DIRDETRABAJO=" + vec[3];
char* formatFile = new char[file.length()+1];
memcpy(formatFile, file.c_str(), file.length()+1);
char* formatFolder= new char[folder.length()+1];
memcpy(formatFolder, folder.c_str(), folder.length()+1);
putenv(formatFile);
putenv(formatFolder);
cout << "CTRSIS: CREATE THREAD " << i << endl;
int ret = pthread_create(&levelOneThreads[i],NULL, readWriteThread, &TubesReference[i]);
if(ret != 0) {
cerr << "Error: pthread_create() failed\n" << endl;
exit(EXIT_FAILURE);
}else{
cout << "CTRSIS: JOIN THREAD " << i << endl;
pthread_join(levelOneThreads[i], NULL);
}
}
//system( "./ctreval" );
return 0;
}
void* readWriteThread(void *arg) {
sleep(3);
WriteIn *dataInOut = (struct WriteIn *) arg;
cout << "CTRSIS: METHOD" << endl;
char c;
while (read(dataInOut->in, &c, 1) > 0) {
write(dataInOut->out, &c, 1);
}
close(dataInOut->in);
close(dataInOut->out);
return NULL;
}
This is the evaluator
#include <iostream>
#include <cctype>
int
main(void) {
int c;
while ((c = std::cin.get()) != EOF) {
c = ::toupper(c);
std::cout << (char) c;
}
return 0;
}

Memory leak when using sqlite3 with C++

The program writes into SQLite database, the messages are received through a wireless module. But somehow there is a memory leak every time a message is received and written to the database, after about 10 000 writes the program is using 1GB of memory.
The documentation for SQLite3 with C++ says that memory leaks are prevented with sqlite3_finalize() and sqlite3_close() which are present:
#include <iostream>
#include <string>
#include <sstream>
#include "sqlite3.h"
using namespace std;
#define DB "test.db"
sqlite3 *dbfile;
bool connectDB();
void disonnectDB();
int insOrUpdate(string s);
int select(string s);
struct messageStruct_t {
float value;
};
bool isOpenDB = false;
int main() {
int counter = 0;
while (1) {
int header = 1;
int message = rand() % 3;
if (message) {
counter ++;
switch (header) {
case 1: {
messageStruct_t recMessage;
recMessage.value = 55;
int receivedSendersID = 2;
//SQL query to get foreign key
stringstream strm_select;
strm_select << "SELECT id FROM table1 WHERE sendersID="
<< receivedSendersID;
string s_select = strm_select.str();
cout << "SQL query: " << s_select << endl;
int sendersID = select(s_select);
cout << "Sender's ID: " << sendersID << endl;
if (sendersID == 0) {
cout << "Error: Sender doesn't exist\n";
} else {
stringstream strm_insert;
strm_insert << "INSERT into table2(id,value,sender_id) values("
<< counter << ", "
<< recMessage.value << ", " << sendersID << ")";
string s_insert = strm_insert.str();
cout << "SQL query: " << s_insert << endl;
insOrUpdate(s_insert);
cout << "Recorded data: " << recMessage.value << endl;
}
}
default: {
break;
}
}
}
}
}
bool connectDB () {
if (sqlite3_open(DB, &dbfile) == SQLITE_OK) {
isOpenDB = true;
return true;
}
return false;
}
void disonnectDB () {
if ( isOpenDB == true ) {
sqlite3_close(dbfile);
}
}
int insOrUpdate(string s) {
if (!connectDB()) {
return 0;
}
char *str = &s[0];
sqlite3_stmt *statement;
int result;
const char *query = str;
if (sqlite3_prepare(dbfile, query, -1, &statement, 0) == SQLITE_OK) {
result = sqlite3_step(statement);
//the documentation says that this destroys the statement and prevents memory leaks
sqlite3_finalize(statement);
return result;
}
//and this destroys the db object and prevents memory leaks
disonnectDB();
return 0;
}
int select(string s) {
if (!connectDB()) {
return 0;
}
char *str = &s[0];
sqlite3_stmt *statement;
const char *query = str;
string returned;
if (sqlite3_prepare(dbfile, query, -1, &statement, 0) == SQLITE_OK) {
int ctotal = sqlite3_column_count(statement);
int res = 0;
while (1) {
res = sqlite3_step(statement);
if (res == SQLITE_ROW) {
for (int i = 0; i < ctotal; i++) {
string s = (char*)sqlite3_column_text(statement, i);
cout << s << " ";
returned = s;
}
cout << endl;
}
if (res == SQLITE_DONE || res == SQLITE_ERROR) {
cout << "done " << endl;
break;
}
}
} else {
cout << "Can't prepare" << endl;
return 0;
}
sqlite3_finalize(statement);
disonnectDB();
int result;
stringstream convert(returned);
if (!(convert >> result)) {
result = 0;
}
return result;
}
CREATE TABLE table1 (
id INTEGER NOT NULL,
sendersID INTEGER,
PRIMARY KEY (id)
);
CREATE TABLE table2 (
id INTEGER NOT NULL,
value FLOAT,
sender_id INTEGER,
FOREIGN KEY(sender_id) REFERENCES table1 (id)
);
INSERT INTO table1(sendersID) values(2);
In your connectDB(..) call , you don't check if the database is already open before opening it again. Your memory leak is probably from the repeated mappings of this database into your memory space.
There may be other issues with this program but the change below to connectDB(..) should help with the leak on every successful insert.
bool connectDB() {
if (false == isOpenDB && sqlite3_open(DB, &dbfile) == SQLITE_OK) {
isOpenDB = true;
}
return isOpenDB;
}
You should definitely use RAII for your connections and also for your statements. There are several places where you return early without cleaning up statements and/or closing the connection.

Threading Segfault when reading members

I am facing some problems when I am trying to read a class variable in my worker thread (That variable was not created withing that thread). Here is my class header with static worker thread function:
class C1WTempReader
{
public:
C1WTempReader(std::string device);
virtual ~C1WTempReader();
void startTemRead();
double& getTemperature();
private:
std::string device;
std::string path;
double temperature;
pthread_t w1Thread;
std::mutex w1Mutex;
bool fileExists(const std::string& filename);
static void * threadHelper(void * arg)
{
return ((C1WTempReader*) arg)->tempReadRun(NULL);
}
void* tempReadRun(void* arg);
};
Here are the crucial methods I am using:
C1WTempReader::C1WTempReader(std::string device)
{
path = W1_PATH + device + W1_SLAVE;
if (!fileExists(path))
{
std::cout << "File " << path << " doesnt exist!" << std::endl;
path.clear();
return;
}
std::cout << "1 wire termometer device path: " << path << std::endl;
}
void C1WTempReader::startTempRead()
{
if(pthread_create(&w1Thread, NULL, threadHelper, NULL) == -1)
{
std::cout << "1W thread creation failed" << std::endl;
}
}
void* C1WTempReader::tempReadRun(void* arg)
{
w1Mutex.lock(); // SEGFAULT
std::string line;
std::ifstream myfile (path.c_str());
if (myfile.is_open())
{
while ( getline (myfile,line) )
{
size_t found = line.find("t=");
if (found != std::string::npos)
{
found += 2;
std::string temp = line.substr(found, 10);
temperature = atof(temp.c_str());
temperature /= 1000;
std::cout << "Temperature: " << temperature << " *C" << std::endl;
}
line.clear();
}
myfile.close();
}
else
{
std::cout << "Unable to open file" << std::endl;
temperature = 1000; // bad value
}
w1Mutex.unlock();
return NULL;
}
double& C1WTempReader::getTemperature()
{
if (pthread_join(w1Thread, NULL))
{
std::cout << "1W Unable to join thread!" << std::endl;
}
return temperature;
}
Segmentation fault happens in the tempReadRun method, as soon as I try to lock the mutex. I didnt have mutexes before and I noticed that it happens whenever I try to read any of the class variables that are created ruring the class creation and are not created within the new thread. What Am I doing wrong?
And heres how I am trying to run this:
string device = "28-00000713a636";
C1WTempReader tempReader(device);
tempReader.startTempRead();
.
.
.
double temp = tempReader.getTemperature();
I have found what the problem was. In the function C1WTempReader::startTempRead():
if(pthread_create(&w1Thread, NULL, threadHelper, NULL) == -1)
{
std::cout << "1W thread creation failed" << std::endl;
}
The last argument of pthread_create had to be changed to this.
You are not passing argument to pthread_create:
if(pthread_create(&w1Thread, NULL, threadHelper, this) == -1)