Проблема в использовании static переменной в QT Creator с версией 5.9.9
сегодня столкнулся с проблемой в qt creator, использую 5.9.9 версию. Проблема заключается в static переменной и в static методе моего класса(MainWindow). Я создал public поле static и попытался init на месте. Но компилятор выдал ошибку non-const static data member must be initialized out of line. Сразу же я попробовал создать static setter и инициализировать static переменную в main до создания объекта, но это не помогло, поэтому решил обойти эту проблему созданием Global переменной, но компилятор выдавал ошибку.Прошу не судить строго, это мой первый вопрос и я новичок. Приведу сразу исходники основные, которые связанны с проблемой
Mainwindow.hpp
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <fstream>
#include "Map.hpp"
#include "popup.hpp"
#include "form.hpp"
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void addNew(QString str); //new word in dictionary
static void setMap(Map &&map)
{
map_ = std::move(map);
}
private slots:
void on_englishword_returnPressed(); //search
void on_search_clicked(); //search
void on_add_clicked();
private:
Ui::MainWindow *ui;
std::ifstream in; //txt stream
std::fstream out; //txt stream
public:
static Map map_;
private:
PopUp * popUp; //notification
Form * form; //confirmation window
};
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <string>
#include <QThread>
#include "List.hpp"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent),
ui(new Ui::MainWindow),
popUp(new PopUp),
form(new Form)
{
ui->setupUi(this);
QPixmap bkgnd("/Users/gvgromov/Desktop/back.jpg");
setWindowIcon(QIcon("/Users/gvgromov/Desktop/ic.jpg"));
bkgnd = bkgnd.scaled(this->size(), Qt::IgnoreAspectRatio);
QPalette palette;
palette.setBrush(QPalette::Background, bkgnd); //background color/theme
this->setPalette(palette);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::addNew(QString str)
{
std::string newStr = str.toStdString();
out.open("/Users/gvgromov/Desktop/dict.txt",std::ios::app);
try
{
map_.parse(newStr);
out << "\r";
out << newStr;
out.close();
popUp->setPopupText("Word and translate was added succesfully!");
popUp->show();
} catch (std::invalid_argument&ob)
{
popUp->setPopupText((QString::fromStdString(ob.what())));
popUp->show();
}
}
void MainWindow::on_englishword_returnPressed()
{
on_search_clicked();
}
void MainWindow::on_search_clicked()
{
List list;
QString buff;
buff = ui->englishword->text();
try
{
QString temp = QString::fromStdString(map_.search(buff.toStdString()).toString());
ui->translate->setText(temp);
}
catch (std::out_of_range &)
{
form->show();
}
}
void MainWindow::on_add_clicked()
{
addNew(ui->englishword->text());
}
main cpp
#include "mainwindow.h"
#include <QPushButton>
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Map map("/Users/gvgromov/Desktop/dict.txt");
MainWindow::setMap(std::move(map));
MainWindow w;
w.setWindowTitle("Dictionary");
w.show();
return a.exec();
}
map.cpp
#include "Map.hpp"
#include <stdexcept>
#include <fstream>
Map::Map() noexcept:
root_(nullptr),
count_(0)
{}
Map::Map(const char* url)
{
std::ifstream in(url);
while (!in.eof())
{
in >> *this;
}
in.close();
}
void Map::add(Pair &&pair)
{
ptr node = std::make_shared<Node>(Node(std::move(pair)));
if (!root_)
{
root_ = node;
return;
}
ptr current = root_;
while (current)
{
if (current->data_.first() == node->data_.first())
{
return;
}
if (current->data_.first() > node->data_.first() && current->left_)
{
current = current->left_;
continue;
} else if (current->data_.first() < node->data_.first() && current->right_)
{
current = current->right_;
continue;
}
++count_;
if (current->data_.first() > node->data_.first())
{
current->left_ = node;
} else if ((current->data_.first() < node->data_.first()))
{
current->right_ = node;
}
return;
}
}
void Map::add(std::string &&word, List &&translate)
{
Pair pair(std::move(word), std::move(translate));
add(std::move(pair));
}
List &Map::search(const std::string &word)
{
if (!root_)
{
throw std::out_of_range("Doesnt exist!");
}
ptr node = root_;
while (node)
{
if (node->data_.first() == word)
{
return node->data_.second();
}
if (node->data_.first() > word)
{
if (node->left_)
{
node = node->left_;
continue;
}
} else
{
if (node->right_)
{
node = node->right_;
continue;
}
}
throw std::out_of_range("Doesnt exist!");
}
}
void Map::remove_root()
{
if (!root_->left_ && !root_->right_)
{
root_.reset();
--count_;
}
if ((!root_->right_ && root_->left_) || (root_->right_ && !root_->left_))
{
--count_;
if (root_->left_)
{
root_ = std::move(root_->left_);
return;
}
root_ = std::move(root_->right_);
return;
}
ptr temp1 = minElement(root_->right_);//todo why without move
std::string swipe = temp1->data_.first();
remove(temp1->data_.first());
root_->data_.first() = swipe;
--count_;
}
void Map::remove(const std::string &word)
{
if (root_->data_.first() == word)
{
remove_root();
return;
}
ptr current = root_;
ptr prev;
while (current && current->data_.first() != word)
{
prev = current;
if (current->data_.first() > word)
{
current = current->left_;
} else
{
current = current->right_;
}
}
if(!current)
{
throw std::invalid_argument("This word doesn't exist!");
}
if (!current->left_ && !current->right_)
{
if (prev->data_.first() > word)
{
prev->left_.reset();
} else
{
prev->right_.reset();
}
--count_;
return;
}
if ((!current->right_ && current->left_) || (current->right_ && !current->left_))
{
ptr temp1;
if (!current->left_)
{
temp1 = std::move(current->right_);
} else
{
temp1 = std::move(current->left_);
}
if (prev->data_.first() > word)
{
prev->left_ = temp1;
} else
{
prev->right_ = temp1;
}
--count_;
return;
}
ptr temp1 = std::move(minElement(current->right_)); //todo why with move
std::string swipe = temp1->data_.first();
remove(temp1->data_.first());
current->data_.first() = swipe;
--count_;
}
List &Map::operator[](std::string &word)
{
return search(word);
}
void Map::parse(std::string &buffer)
{
std::string key, translate;
int pos = 0;
if (buffer.front() == '\n')
{
buffer.erase(buffer.begin());
}
for (const auto &ch:buffer)
{
if (!isalpha(ch) && ch != ' ' && ch != '-')
{
key = buffer.substr(0, pos - 2);
break;
}
pos++;
}
translate = buffer.substr(pos);
List temp1;
temp1.parser(translate);
Pair temp(std::move(key), std::move(temp1));
add(std::move(temp));
}
std::istream &operator>>(std::istream &in, Map &map)
{
std::string buffer;
getline(in, buffer, '\r');
map.parse(buffer);
return in;
}
И самое главное описание ошибки:
Undefined symbols for architecture x86_64:
"MainWindow::map_", referenced from:
MainWindow::setMap(Map&&) in main.o
MainWindow::addNew(QString) in mainwindow.o
MainWindow::on_search_clicked() in mainwindow.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [Dictionary.app/Contents/MacOS/Dictionary] Error 1
00:27:56: Процесс «/usr/bin/make» завершился с кодом 2.
Ошибка при сборке/развёртывании проекта Dictionary (комплект: Desktop Qt 5.9.9 clang 64bit)
Во время выполнения этапа «Сборка»
Ответы (1 шт):
Можно перенести объявление static Map map_;
из заголовочного файла в файл класса (и соответственно реализацию setMap(Map &&map) тоже), тогда должно будет выполниться условие, на которое ругается компилятор. Я проверил, правда, не на clang, а на mingw.
Правда, не до конца понял, зачем используется именно статическая переменная, а не, например, переменная того же типа, которая инициализируется в конструкторе MainWindow:
MainWindow(const char *url, QWidget *parent = nullptr);
в mainwindow.hpp
MainWindow::MainWindow(const char *url, QWidget *parent)
: QMainWindow(parent),
ui(new Ui::MainWindow),
map_(url)
{...
в mainwindow.cpp
MainWindow w("/Users/gvgromov/Desktop/dict.txt");
в main.cpp