Указатель QTcpSocket создает SIGSEGV в представлении.(QT5) - PullRequest
0 голосов
/ 30 сентября 2018

Привет,

У меня есть 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.


Все эти фрагменты кода могут быть перепутаны, поэтому здесь пошаговое объяснение:

  1. Начать сmain(): создать QTcpSocket *, содержащееся в QTTCPSocket class, содержащемся в std::shared_ptr<QTTCPSocket>.
  2. Создать экземпляр ViewStateMachine с shared_ptr, который будет сохранен в экземпляре.Мы назовем его vsm.
  3. Вызов vsm.init(), который создаст экземпляр LoginView с this (vsm).LoginView будет хранить ViewStateMachine экземпляр.
  4. 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указатель.

...