QT多客户端服务端如何优雅管理堆上数据跟踪变量?
优雅解决QT多客户端连接中数据跟踪变量的内存管理问题
针对你手动管理堆内存变量的痛点,有几种更优雅的解决方案,完全避免手动delete和频繁堆分配/释放的烦恼:
方案一:自定义QObject子类封装状态变量(推荐)
利用QT的父子对象内存管理机制,把三个跟踪变量封装到继承自QObject的类中,将这个类的父对象设置为QTcpSocket。当socket断开销毁时,QT会自动递归销毁所有子对象,无需手动管理内存。
步骤1:定义封装类
#include <QObject> #include <QByteArray> class ConnectionState : public QObject { Q_OBJECT public: QByteArray buffer; size_t totalBytesToRead = 0; size_t numOfBytesRead = 0; explicit ConnectionState(QObject *parent = nullptr) : QObject(parent) {} };
步骤2:修改newConnection函数
void myNetworkClass::newConnection() { QTcpSocket *newSocket = server.nextPendingConnection(); if(newSocket == nullptr) { return; } ++s_ConnectionsCount; // 将socket作为父对象,内存由QT自动管理 ConnectionState *state = new ConnectionState(newSocket); // 信号槽传递封装后的对象 QObject::connect(newSocket, &QAbstractSocket::disconnected, this, [=]() { this->onDisconnection(newSocket, state); }); QObject::connect(newSocket, &QIODevice::readyRead, this, [=]() { this->onRecvData(newSocket, state); }); }
步骤3:调整回调函数
无需手动delete,直接使用封装对象:
void myNetworkClass::onDisconnection(QTcpSocket *socket, ConnectionState *state) { // 执行断开后的清理逻辑 // 不需要delete state,socket销毁时会自动删除它 socket->deleteLater(); } void myNetworkClass::onRecvData(QTcpSocket *socket, ConnectionState *state) { // 直接操作封装的变量 state->buffer.append(socket->readAll()); // ... 其他数据处理逻辑 }
方案二:使用智能指针自动管理内存
利用C++智能指针(如std::shared_ptr或QSharedPointer)自动跟踪引用计数,当最后一个引用消失时自动释放内存,无需手动delete。
修改newConnection函数
#include <memory> void myNetworkClass::newConnection() { QTcpSocket *newSocket = server.nextPendingConnection(); if(newSocket == nullptr) { return; } ++s_ConnectionsCount; // 用智能指针分配内存 auto buffer = std::make_shared<QByteArray>(); auto totalBytesToRead = std::make_shared<size_t>(0); auto numOfBytesRead = std::make_shared<size_t>(0); // lambda捕获智能指针,自动维持引用计数 QObject::connect(newSocket, &QAbstractSocket::disconnected, this, [=]() { this->onDisconnection(newSocket); // 无需手动delete,智能指针会在引用计数归零时自动释放 socket->deleteLater(); }); QObject::connect(newSocket, &QIODevice::readyRead, this, [=]() { this->onRecvData(newSocket, buffer.get(), totalBytesToRead.get(), numOfBytesRead.get()); }); }
该方案无需修改现有回调函数的参数结构,适合快速改造现有代码。
方案三:利用QT的属性系统绑定变量
通过QObject::setProperty将变量绑定到QTcpSocket对象上,借助socket的生命周期自动管理这些属性。不过该方案更适合简单类型,复杂类型(如QByteArray)的修改需要处理值传递的问题。
修改newConnection函数
void myNetworkClass::newConnection() { QTcpSocket *newSocket = server.nextPendingConnection(); if(newSocket == nullptr) { return; } ++s_ConnectionsCount; // 初始化socket属性 newSocket->setProperty("buffer", QByteArray()); newSocket->setProperty("totalBytesToRead", QVariant::fromValue<qulonglong>(0)); newSocket->setProperty("numOfBytesRead", QVariant::fromValue<qulonglong>(0)); QObject::connect(newSocket, &QAbstractSocket::disconnected, this, [=]() { this->onDisconnection(newSocket); socket->deleteLater(); }); QObject::connect(newSocket, &QIODevice::readyRead, this, [=]() { this->onRecvData(newSocket); }); }
调整onRecvData函数
void myNetworkClass::onRecvData(QTcpSocket *socket) { // 读取并修改属性 QByteArray buffer = socket->property("buffer").value<QByteArray>(); buffer.append(socket->readAll()); socket->setProperty("buffer", buffer); qulonglong total = socket->property("totalBytesToRead").value<qulonglong>(); // ... 其他数据处理逻辑 }
内容的提问来源于stack exchange,提问作者noob_user
相关产品推荐
相关产品推荐

