【问题标题】:Public member not initialized公共成员未初始化
【发布时间】:2023-03-27 17:35:02
【问题描述】:

我正在制作一个客户端服务器应用程序,服务器有一个 GUI。我正在使用 Qt。 对于通信,我使用管道。

我已将服务器应用程序分为后端和 GUI。后端有一个 PipeServer 类,在 GUI 中,我重写了 onReceiveMessage 等函数。

在我决定添加 std::queue 作为基类成员之前,一切正常。

在应用程序开始时,我遇到了一个异常,经过检查,我的队列似乎不是以 0 个元素开始的。事实上,队列似乎根本没有初始化。有两种可能性:可能是因为我的 GUI 类继承了 2 个类,并且不知何故第二个基类,即我的 PipeServer 没有正确初始化其成员,或者可能是因为 pipeServerGUI 对象被移动到不同的线程QT。

关于如何解决这个问题的任何想法?

相关代码:

class HookServer
{
    PIPEINST Pipe[INSTANCES]; 
    HANDLE hEvents[INSTANCES]; 

    VOID DisconnectAndReconnect(DWORD); 
    BOOL ConnectToNewClient(HANDLE, LPOVERLAPPED); 
    VOID GetAnswerToRequest(LPPIPEINST); 

public:
    std::queue<std::string> messages;

    int init(std::string pipename);
    int run();
    virtual void onNewConnection() {};
    virtual void onReceiveMessage(std::string message) {};
};

class HookServerGUI : public QObject, public HookServer
{
    Q_OBJECT
    void onReceiveMessage(std::string message);
    void onNewConnection();

    public slots:

    void doWork() {
        init("\\\\.\\pipe\\hookpipe");
        run();
    }

    signals:
    void signalGUI(QString message);
};

    //GUIServerCreation

    QThread *thread = new QThread;
    HookServerGUI* worker = new HookServerGUI;
    QObject::connect(worker,SIGNAL(signalGUI(const QString&)),this,SLOT(processMessage(const QString&)));

    worker->moveToThread(thread);
    thread->start();



    QMetaObject::invokeMethod(worker, "doWork", Qt::QueuedConnection);

编辑:

异常是访问冲突异常。它发生在这部分代码中:

VOID HookServer::GetAnswerToRequest(LPPIPEINST pipe)
{
    onReceiveMessage(pipe->chRequest);
    if(!messages.empty())
    {
        std::string s = messages.front();
        messages.pop();
        strcpy(pipe->chReply,s.c_str());
        pipe->cbToWrite = strlen(s.c_str()+1);
    }
}

由于 messages.empty() 返回了一个巨大的数字,它尝试读取第一个对象并以某种方式失败。

也没有 PipeServerGUI 构造函数。

编辑2:

我通过在new HookServerGUI(); 后面加上括号解决了部分问题

问题是该函数仍然不起作用,并引发访问冲突异常。它发生在 front() 行。在调试器中检查时,该函数确实有 1 个元素,所以不是因为它是空的。有什么想法吗?

EDIT3:

在第二次运行时,不幸的是 queue.size() 仍然不正确。对我来说,这就像一场数据竞赛。

【问题讨论】:

  • 我认为您的两个选项中的任何一个都不可能成为候选人。 HookServer 没有实现构造函数,因此默认构造函数应该调用其成员的默认构造函数(即 std::queue)。我看不出线程如何成为问题的一部分,因为 HookServerGUI 要么被构造,要么没有。错误在哪里?是在 HookServerGUI 的构造函数期间吗?异常类型是什么?
  • 看来我部分解决了问题,我没有在new HookServerGUI后面加括号。
  • GetAnswerToRequest() 是一个私有函数。谁叫它?也许您应该尝试在 HookServer 中创建构造函数和析构函数并记录一些内容或在其中放置断点,以确保在调用此函数之前您的对象正在被创建而不是被删除。
  • @sbaker 它在 run() 函数中被调用。现在我将队列更改为字符串,并将其显式设置为空字符串。
  • 风格挑剔:Qt::QueuedConnection 中的invokeMethod 是不必要的,自动连接将正常工作。 QObject::connect 可以传递规范化签名,所以 SIGNAL(signalGUI(QString))SLOT(processMessage(QString)) 就足够了——这样写的更少。 slot 方法的签名应该是void signalGUI(const QString &amp;) - 以这种方式在共享字符串数据上保存detach()

标签: c++ qt class initialization


【解决方案1】:

问题出在您没有显示的代码中,看起来像是内存错误的经典案例。某处的某些代码正在写入它不拥有的内存。可能您在使用 winapi 的方式上存在错误。您需要创建一个最小的、独立的测试用例。

我认为你可能会因为不使用QLocalSocket而自取其辱:在 Windows 上,它是一个命名管道 - 正是你想要的。

此外,这是 C++ 代码。根本没有理由将 PIPEINST 或 HANDLE 放入原始 C 数组。使用QVectorstd::vector。可能其余的代码都充满了类似的 C 主义,并且某些地方出了问题。

我不会忽视缓冲区溢出,因为显然您忽略了 PIPEINST 中缓冲区的大小 - strcpy 可能会溢出缓冲区。我也不确定 PIPEINST from the example code 使用的字符类型与 std::string::c_str() 返回的字符类型相同。

即使您想使用不带QLocalSocket 的显式管道来实现您的代码,您仍然应该使用C++、QString 等并了解您的数据发生了什么。

【讨论】:

  • 我想将 Qt GUI 与后端分离,以便稍后我能够拥有一个控制台应用程序。
  • @BartlomiejLewandowski:您确实明白 Qt 核心与 gui 无关,并且非常适合在服务器代码中使用,对吧?后端、前端的 gui 和控制台前端都可以使用 Qt 编写。
  • @BartlomiejLewandowski:例如,Qt interoperates nicely 与护士一起在 Unix/Linux 上创建控制台应用程序。
  • 但这似乎是一个很大的跳跃。这就像将 boost 用于一个小功能。我不想强迫可能想要使用代码的人必须拥有 Qt。
  • 我认为问题不在于管道代码本身。因为在运行它之前,我没有初始化它们。明天我将尝试制作一个独立的示例。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-08-16
  • 1970-01-01
  • 1970-01-01
  • 2011-07-14
  • 2019-09-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多