Reputation: 3
The problem I'm having has been discussed multiple times, but I still don't understand how to fix the issue I'm having. I used to program in C++ a lot but switched over to Java for a while due to work. I'm getting back into C++ and I'm now having a lot of issues with memory management/pointers/references etc. This problem stems from that.
For context, these are files for a Qt 5.14 project that I'm working on.
The problem is that I have a private class variable named loggerLevel
and the method that creates the segmentation fault error is getLevel
which just returns the value of the loggerLevel. The that is supposed to be stored in the variable is an enum named Level that is defined in the header of the class.
I don't know if the problem stems from my lack of knowledge or if I am misunderstanding something about how classes work in C++, or if its something completely different. In any case, if anyone can help me out that would be great :)
--- Source code below ---
logger.cpp
#include "logger.h"
QString debugHTML = "<font color=\"gray\">";
QString infoHTML = "<font color=\"black\">";
QString warningHTML = "<font color=\"yellow\">";
QString errorHTML = "<font color=\"orange\">";
QString criticalHTML = "<font color=\"red\">";
QString endHTML = "</font><br>";
Logger::Logger(QObject *parent,
QString fileName,
QTextEdit *editor) : QObject(parent)
{
m_editor = editor;
m_showDate = true;
loggerLevel = Level::INFO;
if (!fileName.isEmpty()) {
file = new QFile;
file->setFileName(fileName);
file->open(QIODevice::Append | QIODevice::Text);
}
}
void Logger::write(const QString &value) {
QString text = value;
if (m_showDate) {
text = QDateTime::currentDateTime()
/*.toString("dd.MM.yyyy hh:mm:ss ") + text;*/
.toString("hh:mm:ss: ") + text;
}
QTextStream out(file);
out.setCodec("UTF-8");
if (file != 0) {
out << text;
} else {
//TODO: add QMessageBox here with error
}
//Adds HTML color/formatting
switch(loggerLevel)
{
case DEBUG: text = debugHTML + text; break;
case INFO: text = infoHTML + text; break;
case WARNING: text = warningHTML + text; break;
case ERROR: text = errorHTML + text; break;
case CRITICAL: text = criticalHTML + text; break;
default: text = infoHTML + text; break;
}
text = text + endHTML;
if (m_editor != 0) {
m_editor->insertHtml(text);
} else {
//TODO: add QMessageBox here with error
}
}
void Logger::write(const Level &level, const QString &value) {
Level prevLoggerLevel = Logger::getLevel();
Logger::setLevel(level);
write(value);
Logger::setLevel(prevLoggerLevel);
}
//--------Setters--------
void Logger::setLevel(const Level &level) {
loggerLevel = level;
}
void Logger::setShowDateTime(bool value) {
m_showDate = value;
}
//--------Getters--------
Logger::Level Logger::getLevel() {
return loggerLevel;
}
Logger::~Logger() {
if (file != 0) {
file->close();
}
}
logger.h
#ifndef LOGGER_H
#define LOGGER_H
#include <QObject>
#include <QPlainTextEdit>
#include <QFile>
#include <QTextStream>
#include <QDateTime>
class Logger : public QObject
{
Q_OBJECT
public:
explicit Logger(QObject *parent,
QString fileName = 0,
QTextEdit *editor = 0);
~Logger();
void setShowDateTime(bool value);
enum Level
{
DEBUG,
INFO,
WARNING,
ERROR,
CRITICAL
};
private:
QFile *file;
QTextEdit *m_editor;
bool m_showDate;
Level loggerLevel;
signals:
public slots:
void write(const QString &value);
void write(const Level &level, const QString &value);
void setLevel(const Level &level);
Level getLevel();
};
#endif // LOGGER_H
MainWindow.cpp
#include <string>
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "settingsdialog.h"
#include "logger.h"
Logger *logger;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
QString logFileName = "log.txt";
Logger *logger = new Logger(this, logFileName, ui->loggerOutput);
logger->write(Logger::Level::INFO, "Logger Initilized!");
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_toolButton_clicked()
{
SettingsDialog settingsDialog;
settingsDialog.setModal(true);
settingsDialog.exec();
}
//Left Side of controller
void MainWindow::on_s_leftJoystickX_Throttle_sliderMoved(int position)
{ ui->l_leftJoystickX->setText(QStringLiteral("X-Axis: %1%").arg(position)); }
void MainWindow::on_s_leftJoystickY_Throttle_sliderMoved(int position)
{ ui->l_leftJoystickY->setText(QStringLiteral("Y-Axis: %1%").arg(position)); }
void MainWindow::on_s_leftTrigger_Throttle_sliderMoved(int position)
{ ui->l_leftTrigger->setText(QStringLiteral("Trigger: %1%").arg(position)); }
void MainWindow::on_s_joystickThrottle_sliderMoved(int position)
{ ui->l_joystickThrottle->setText(QStringLiteral("Throttle: %1%").arg(position)); }
//Right Side of controller
void MainWindow::on_s_rightJoystickX_Throttle_sliderMoved(int position)
{ ui->l_rightJoystickX->setText(QStringLiteral("X-Axis: %1%").arg(position)); }
void MainWindow::on_s_rightJoystickY_Throttle_sliderMoved(int position)
{ ui->l_rightJoystickY->setText(QStringLiteral("Y-Axis: %1%").arg(position)); }
void MainWindow::on_s_rightTrigger_Throttle_sliderMoved(int position)
{ ui->l_rightTrigger->setText(QStringLiteral("Trigger: %1%").arg(position)); }
void MainWindow::on_s_keyboardThrottle_sliderMoved(int position)
{ ui->l_keyboardThrottle->setText(QStringLiteral("Throttle: %1%").arg(position)); }
void MainWindow::on_b_keyboardAction_1_clicked()
{
logger->write(Logger::Level::CRITICAL, "test");
}
There are more files, but I believe they are not relevant to the problem, if needed I can post the other files aswell.
-----Solution!-----
@churill Solution explains what needs to be done to fix this problem but I also will detail it below to complete this question.
Since I had already made a forward declaration of logger
Logger *logger
at the top of MainWindow.cpp, creating a new Logger object
Logger *logger = new Logger(this, logFileName, ui->loggerOutput);
is unnecessary so calling the forward declarations variable name instead of creating a new Logger object
logger = new Logger(this, logFileName, ui->loggerOutput);
fixes the problem!
Upvotes: 0
Views: 1451
Reputation: 11340
From first glance:
Logger *logger = new Logger(this, logFileName, ui->loggerOutput);
creates an object that has nothing to do with the global variable logger
which is never initialized. Maybe you meant to write only
logger = new Logger(this, logFileName, ui->loggerOutput);
to initialize this global variable.
To somewhat address the title of your question: Yes you actually can call functions on invalid pointers, but then the this
-pointer is not valid, thus accessing a member variable causes the seg-fault.
Upvotes: 2