Привет,
У меня есть SIGSEGV, когда я хочу использовать QTcpSocket со следующим кодом.(более подробное объяснение в самом низу)
Функция для создания QTTCPSocket (которая будет хранить указатель QTcpSocket):
std::shared_ptr<QTTCPSocket> createQtSocket(std::string host, unsigned int port)
{
QTcpSocket *sock = new QTcpSocket;
sock->connectToHost(QHostAddress(QString::fromStdString(host)), port);
if (!sock->waitForConnected())
throw std::runtime_error("Connection refused");
return std::make_shared<QTTCPSocket>(sock);
}
Класс QTTCPSocket:
class QTTCPSocket {
public:
QTTCPSocket(QTcpSocket *socket)
: _socket(socket)
{};
~QTTCPSocket() = default;
void send(const std::string &msg)
{
std::cout << msg << std::endl;
_socket->write(&msg[0], static_cast<qint64>(msg.length())); // produces a SIGSEGV if called from a qt event (a button for example)
_socket->waitForBytesWritten(0);
}
private:
QTcpSocket *_socket;
};
Основная функция:
int main()
{
std::shared_ptr<QTTCPSocket> socket = createQtSocket("127.0.0.1", 33333);
ViewStateMachine vsm(socket);
vsm.init();
vsm.start();
}
Класс ViewStateMachine (hpp):
class ViewStateMachine {
public:
ViewStateMachine(std::shared_ptr<QTTCPSocket> sock);
void init();
void start();
std::shared_ptr<QTTCPSocket> getSock();
private:
LoginView *_loginView;
std::shared_ptr<QTTCPSocket> _sock;
};
Класс ViewStateMachine (cpp):
#include "ViewStateMachine.hpp"
ViewStateMachine::ViewStateMachine(std::shared_ptr<QTTCPSocket> socket)
: _sock(std::move(socket))
{
}
void ViewStateMachine::init()
{
_loginView = new LoginView(this);
_loginView->init();
}
void ViewStateMachine::start()
{
_loginView->show();
}
std::shared_ptr<QTTCPSocket> ViewStateMachine::getSock()
{
_sock->send("test1"); // SIGSEGV inside (check above)
return _sock; // if I remove _sock->send("test1"), it SIGSEGV in the shared_ptr's constructor (only if called from a qt event (a button for example)
}
LoginView - это пассивный класс, который регистрирует событие с QObject::connect(_connectBtn, SIGNAL(clicked()), this, SLOT(onClick_connectBtn()));
с onClick_connectBtn()
членомфункция LoginView
.
Все эти фрагменты кода могут быть перепутаны, поэтому здесь пошаговое объяснение:
- Начать с
main()
: создать QTcpSocket *
, содержащееся в QTTCPSocket class
, содержащемся в std::shared_ptr<QTTCPSocket>
. - Создать экземпляр
ViewStateMachine
с shared_ptr
, который будет сохранен в экземпляре.Мы назовем его vsm
. - Вызов
vsm.init()
, который создаст экземпляр LoginView
с this
(vsm
).LoginView
будет хранить ViewStateMachine
экземпляр. - Call
vsm.start()
, который будет вызывать _loginView.show()
(из QWidget QT), он покажет вид входа в систему.
Всеработает хорошо, и мы можем видеть представление входа в систему.
Однако, если я хочу использовать свой сокет в LoginView: * когда я хочу использовать его из _loginView->init()
или в конструкторе LoginView, он работает хорошо!* когда я хочу использовать его из LoginView::onClick_connectBtn
(вызывается QT, возможно, в специальной среде, такой как конструктор, не уверен), он генерирует SIGSEGV, где я комментировал выше в коде (конструктор shared_ptr или функция записи из QT 'сокет).
Чтобы получить сокет от LoginView
, я использую ViewStateMachine::getSock()
(_viewStateMachine->getSock()
).
Valgrind показывает
pure virtual method called
terminate called without an active exception
Конструктор shared_ptr создает SIGSEGV, когда он использует свой мьютекс для увеличения значения.Запись SIGSEGV, когда я использую _socket
(гнездо QT ').Адрес указателя не изменился от начала до конца.
Если есть какой-либо другой вопрос, пожалуйста, задавайте!
Большое спасибо за помощь:).
РЕДАКТИРОВАТЬ: Это работает, если я заменю каждый std :: shared_ptr на Cуказатель.