C++ 在不影响信号/插槽机制的情况下处理方法内部动态分配导致的内存泄漏

C++ 在不影响信号/插槽机制的情况下处理方法内部动态分配导致的内存泄漏,c++,qt,memory-leaks,C++,Qt,Memory Leaks,在本地函数中使用动态分配时,如何处理内存泄漏而不影响信号/插槽机制。我正在使用向服务器发送请求的客户端应用程序 以下是我的设想: MyClientApplication::sendRequestToServer() { QString url_string = http://..... // a url request QUrl url = url_string; QNetworkAccessManager *qnam = new QNetworkAccessMana

在本地函数中使用动态分配时,如何处理内存泄漏而不影响信号/插槽机制。我正在使用向服务器发送请求的客户端应用程序

以下是我的设想:

MyClientApplication::sendRequestToServer()
{
    QString url_string = http://.....  // a url request
    QUrl url = url_string;

    QNetworkAccessManager *qnam = new QNetworkAccessManager();

    connect(qnam, SIGNAL(finished(QNetworkReply *)), this, SLOT(handleResponseFromServer(QNetworkReply *)));
    QNetworkRequest request(url);
    QNetworkReply *reply = qnam->post(request);
}
我在客户端应用程序的一个成员函数中创建了许多这样的请求,每次都使用动态创建的
QNetworkAccessManager
对象将请求发送到服务器

由于动态分配
qnam
,如何处理内存泄漏?如果我只在堆栈上创建
qnam
对象,那么当
sendRequestToServer()
从调用返回时,信号/插槽机制将如何工作


我希望在不影响信号/插槽机制的情况下解决内存泄漏问题。

使用QNetworkAccessManager指针(
QNetworkAccessManager*qnam;
)作为类中的成员变量,并且只在类构造函数中分配一次(调用
qnam=new QNetworkAccessManager(此)
它可以接受父对象,因此在构造时可以将此作为父对象传递,这样就不需要析构函数中的delete调用)

LE:另请参阅文档中的注释(它与QNetworkAccessManager无关,但如果不调用
deleteLater()
),则答复将泄漏):

注意:请求完成后,用户有责任在适当的时间删除QNetworkReply对象。不要在连接到finished()的插槽中直接删除它。您可以使用deleteLater()函数


有几种方法可以解决这个问题,如果不更彻底地理解您的用例,就很难说哪种方法在您的特定场景中是最好的

然而,您的困惑可能是,如果您使用指针或堆栈对象,它对
connect
机制很重要。唯一需要确保的是对象生命周期足够好

这意味着,该对象必须在需要时可用,因此,例如,在离开desidered的范围后,该对象仍然必须存在。它可以通过堆和堆栈对象来实现

Qt父子层次结构 您可以简单地使用
MyClientApplication
QObject子类(直接或间接)作为网络访问管理器的父类。这样,可以保证只有当父对象停止时,即当MyClientApplication对象停止存在时,子对象才会被销毁。注意,在这种情况下,当对象离开相应方法的作用域时,它不会被破坏,这就是为什么它可以工作的原因。稍后将根据上述规则将其删除

以下是必要的代码更改:

MyClientApplication::sendRequestToServer()
{

    QString url_string = http://.....  // a url request
    QUrl url = url_string;

    QNetworkAccessManager *qnam = new QNetworkAccessManager(this); // This is how you set up the parent on the child    

    connect(qnam, SIGNAL(finished(QNetworkReply *)), this, SLOT(handleResponseFromServer(QNetworkReply *)));

    QNetworkRequest request(url);
    QNetworkReply *reply = qnam->post(request); // Naturally, you will need the stack object syntax here, respectively
}

This will probably be the easiest option for you to use based on the knowledge of your current code, so stick to this.
class MyClientApplication...
{
    ...
    QNetworkAccessManager qnam; // This is the new member variable
    ...
};

MyClientApplication::sendRequestToServer()
{

    QString url_string = http://.....  // a url request
    QUrl url = url_string;

    // Here you need to get the address of the object since the connect function expects a pointer
    connect(&qnam, SIGNAL(finished(QNetworkReply *)), this, SLOT(handleResponseFromServer(QNetworkReply *)));

    QNetworkRequest request(url);
    QNetworkReply *reply = qnam.post(request); // Naturally, you will need the stack object syntax here, respectively
}

This would probably be the easiest option when you cannot use the Qt parent-child hierarchy.
class MyClientApplication...
{
    ...
    QNetworkAccessManager *qnam; // This is the new member variable
    ...
};

MyClientApplication::MyClientApplication(...)
: qnam(new QNetworkAccessManager())
...
{
    ...
}

MyClientApplication::~MyClientApplication()
{
    delete qnam;
    qnam = 0;
    ...
}

MyClientApplication::sendRequestToServer()
{

    QString url_string = http://.....  // a url request
    QUrl url = url_string;

    // Construction removed here since that is done in the constructor

    connect(qnam, SIGNAL(finished(QNetworkReply *)), this, SLOT(handleResponseFromServer(QNetworkReply *)));

    QNetworkRequest request(url);
    QNetworkReply *reply = qnam->post(request);
}

This is a bad practice in C++ in general to deal with the raw pointer explicitly. In certain cases, it makes sense, but if you do not have extra memory and performance concerns, this is not the way to go for. It is also error-prone if you forget to delete the raw pointer yourself.
class MyClientApplication...
{
    ...
    QPointer<QNetworkAccessManager> qnam; // This is the new member variable
    ...
};

MyClientApplication::MyClientApplication(...)
: qnam(new QNetworkAccessManager())
...
{
    ...
}

MyClientApplication::sendRequestToServer()
{

    QString url_string = http://.....  // a url request
    QUrl url = url_string;

    // Construction removed here since that is done in the constructor

    connect(qnam, SIGNAL(finished(QNetworkReply *)), this, SLOT(handleResponseFromServer(QNetworkReply *)));

    QNetworkRequest request(url);
    QNetworkReply *reply = qnam->post(request);
}

This is a good practice in C++ in general to deal with pointers due to the simplified maintenance. However, if you have a simple code as you pasted, this is probably an overengineered solution.
堆栈上的成员变量 您可以简单地使用堆栈对象,在构造过程中初始化。这将具有前面提到的必要生命周期,因为它仅在销毁
MyClientApplication
类的过程中被销毁

以下是必要的代码更改:

MyClientApplication::sendRequestToServer()
{

    QString url_string = http://.....  // a url request
    QUrl url = url_string;

    QNetworkAccessManager *qnam = new QNetworkAccessManager(this); // This is how you set up the parent on the child    

    connect(qnam, SIGNAL(finished(QNetworkReply *)), this, SLOT(handleResponseFromServer(QNetworkReply *)));

    QNetworkRequest request(url);
    QNetworkReply *reply = qnam->post(request); // Naturally, you will need the stack object syntax here, respectively
}

This will probably be the easiest option for you to use based on the knowledge of your current code, so stick to this.
class MyClientApplication...
{
    ...
    QNetworkAccessManager qnam; // This is the new member variable
    ...
};

MyClientApplication::sendRequestToServer()
{

    QString url_string = http://.....  // a url request
    QUrl url = url_string;

    // Here you need to get the address of the object since the connect function expects a pointer
    connect(&qnam, SIGNAL(finished(QNetworkReply *)), this, SLOT(handleResponseFromServer(QNetworkReply *)));

    QNetworkRequest request(url);
    QNetworkReply *reply = qnam.post(request); // Naturally, you will need the stack object syntax here, respectively
}

This would probably be the easiest option when you cannot use the Qt parent-child hierarchy.
class MyClientApplication...
{
    ...
    QNetworkAccessManager *qnam; // This is the new member variable
    ...
};

MyClientApplication::MyClientApplication(...)
: qnam(new QNetworkAccessManager())
...
{
    ...
}

MyClientApplication::~MyClientApplication()
{
    delete qnam;
    qnam = 0;
    ...
}

MyClientApplication::sendRequestToServer()
{

    QString url_string = http://.....  // a url request
    QUrl url = url_string;

    // Construction removed here since that is done in the constructor

    connect(qnam, SIGNAL(finished(QNetworkReply *)), this, SLOT(handleResponseFromServer(QNetworkReply *)));

    QNetworkRequest request(url);
    QNetworkReply *reply = qnam->post(request);
}

This is a bad practice in C++ in general to deal with the raw pointer explicitly. In certain cases, it makes sense, but if you do not have extra memory and performance concerns, this is not the way to go for. It is also error-prone if you forget to delete the raw pointer yourself.
class MyClientApplication...
{
    ...
    QPointer<QNetworkAccessManager> qnam; // This is the new member variable
    ...
};

MyClientApplication::MyClientApplication(...)
: qnam(new QNetworkAccessManager())
...
{
    ...
}

MyClientApplication::sendRequestToServer()
{

    QString url_string = http://.....  // a url request
    QUrl url = url_string;

    // Construction removed here since that is done in the constructor

    connect(qnam, SIGNAL(finished(QNetworkReply *)), this, SLOT(handleResponseFromServer(QNetworkReply *)));

    QNetworkRequest request(url);
    QNetworkReply *reply = qnam->post(request);
}

This is a good practice in C++ in general to deal with pointers due to the simplified maintenance. However, if you have a simple code as you pasted, this is probably an overengineered solution.
堆上的成员变量 您可以简单地使用一个heap对象,在构建过程中创建,在构建过程中销毁。这将具有前面提到的必要生命周期,因为它仅在销毁
MyClientApplication
类的过程中被销毁

以下是必要的代码更改:

MyClientApplication::sendRequestToServer()
{

    QString url_string = http://.....  // a url request
    QUrl url = url_string;

    QNetworkAccessManager *qnam = new QNetworkAccessManager(this); // This is how you set up the parent on the child    

    connect(qnam, SIGNAL(finished(QNetworkReply *)), this, SLOT(handleResponseFromServer(QNetworkReply *)));

    QNetworkRequest request(url);
    QNetworkReply *reply = qnam->post(request); // Naturally, you will need the stack object syntax here, respectively
}

This will probably be the easiest option for you to use based on the knowledge of your current code, so stick to this.
class MyClientApplication...
{
    ...
    QNetworkAccessManager qnam; // This is the new member variable
    ...
};

MyClientApplication::sendRequestToServer()
{

    QString url_string = http://.....  // a url request
    QUrl url = url_string;

    // Here you need to get the address of the object since the connect function expects a pointer
    connect(&qnam, SIGNAL(finished(QNetworkReply *)), this, SLOT(handleResponseFromServer(QNetworkReply *)));

    QNetworkRequest request(url);
    QNetworkReply *reply = qnam.post(request); // Naturally, you will need the stack object syntax here, respectively
}

This would probably be the easiest option when you cannot use the Qt parent-child hierarchy.
class MyClientApplication...
{
    ...
    QNetworkAccessManager *qnam; // This is the new member variable
    ...
};

MyClientApplication::MyClientApplication(...)
: qnam(new QNetworkAccessManager())
...
{
    ...
}

MyClientApplication::~MyClientApplication()
{
    delete qnam;
    qnam = 0;
    ...
}

MyClientApplication::sendRequestToServer()
{

    QString url_string = http://.....  // a url request
    QUrl url = url_string;

    // Construction removed here since that is done in the constructor

    connect(qnam, SIGNAL(finished(QNetworkReply *)), this, SLOT(handleResponseFromServer(QNetworkReply *)));

    QNetworkRequest request(url);
    QNetworkReply *reply = qnam->post(request);
}

This is a bad practice in C++ in general to deal with the raw pointer explicitly. In certain cases, it makes sense, but if you do not have extra memory and performance concerns, this is not the way to go for. It is also error-prone if you forget to delete the raw pointer yourself.
class MyClientApplication...
{
    ...
    QPointer<QNetworkAccessManager> qnam; // This is the new member variable
    ...
};

MyClientApplication::MyClientApplication(...)
: qnam(new QNetworkAccessManager())
...
{
    ...
}

MyClientApplication::sendRequestToServer()
{

    QString url_string = http://.....  // a url request
    QUrl url = url_string;

    // Construction removed here since that is done in the constructor

    connect(qnam, SIGNAL(finished(QNetworkReply *)), this, SLOT(handleResponseFromServer(QNetworkReply *)));

    QNetworkRequest request(url);
    QNetworkReply *reply = qnam->post(request);
}

This is a good practice in C++ in general to deal with pointers due to the simplified maintenance. However, if you have a simple code as you pasted, this is probably an overengineered solution.
堆上具有智能指针的成员变量 您可以简单地使用一个heap对象,在构建过程中创建,在构建过程中销毁。这将具有前面提到的必要生命周期,因为它仅在销毁
MyClientApplication
类的过程中被销毁。您将使用智能指针为您处理自动销毁

以下是必要的代码更改:

MyClientApplication::sendRequestToServer()
{

    QString url_string = http://.....  // a url request
    QUrl url = url_string;

    QNetworkAccessManager *qnam = new QNetworkAccessManager(this); // This is how you set up the parent on the child    

    connect(qnam, SIGNAL(finished(QNetworkReply *)), this, SLOT(handleResponseFromServer(QNetworkReply *)));

    QNetworkRequest request(url);
    QNetworkReply *reply = qnam->post(request); // Naturally, you will need the stack object syntax here, respectively
}

This will probably be the easiest option for you to use based on the knowledge of your current code, so stick to this.
class MyClientApplication...
{
    ...
    QNetworkAccessManager qnam; // This is the new member variable
    ...
};

MyClientApplication::sendRequestToServer()
{

    QString url_string = http://.....  // a url request
    QUrl url = url_string;

    // Here you need to get the address of the object since the connect function expects a pointer
    connect(&qnam, SIGNAL(finished(QNetworkReply *)), this, SLOT(handleResponseFromServer(QNetworkReply *)));

    QNetworkRequest request(url);
    QNetworkReply *reply = qnam.post(request); // Naturally, you will need the stack object syntax here, respectively
}

This would probably be the easiest option when you cannot use the Qt parent-child hierarchy.
class MyClientApplication...
{
    ...
    QNetworkAccessManager *qnam; // This is the new member variable
    ...
};

MyClientApplication::MyClientApplication(...)
: qnam(new QNetworkAccessManager())
...
{
    ...
}

MyClientApplication::~MyClientApplication()
{
    delete qnam;
    qnam = 0;
    ...
}

MyClientApplication::sendRequestToServer()
{

    QString url_string = http://.....  // a url request
    QUrl url = url_string;

    // Construction removed here since that is done in the constructor

    connect(qnam, SIGNAL(finished(QNetworkReply *)), this, SLOT(handleResponseFromServer(QNetworkReply *)));

    QNetworkRequest request(url);
    QNetworkReply *reply = qnam->post(request);
}

This is a bad practice in C++ in general to deal with the raw pointer explicitly. In certain cases, it makes sense, but if you do not have extra memory and performance concerns, this is not the way to go for. It is also error-prone if you forget to delete the raw pointer yourself.
class MyClientApplication...
{
    ...
    QPointer<QNetworkAccessManager> qnam; // This is the new member variable
    ...
};

MyClientApplication::MyClientApplication(...)
: qnam(new QNetworkAccessManager())
...
{
    ...
}

MyClientApplication::sendRequestToServer()
{

    QString url_string = http://.....  // a url request
    QUrl url = url_string;

    // Construction removed here since that is done in the constructor

    connect(qnam, SIGNAL(finished(QNetworkReply *)), this, SLOT(handleResponseFromServer(QNetworkReply *)));

    QNetworkRequest request(url);
    QNetworkReply *reply = qnam->post(request);
}

This is a good practice in C++ in general to deal with pointers due to the simplified maintenance. However, if you have a simple code as you pasted, this is probably an overengineered solution.
类MyClientApplication。。。
{
...
QPointer qnam;//这是新的成员变量
...
};
MyClientApplication::MyClientApplication(…)
:qnam(新的QNetworkAccessManager())
...
{
...
}
MyClientApplication::sendRequestToServer()
{
QString url_字符串=http://.....  //url请求
QUrl url=url\u字符串;
//此处删除了构造,因为这是在构造函数中完成的
连接(qnam,信号(完成(QNetworkReply*)),此插槽(HandlerResponseFromServer(QNetworkReply*));
QNetworkRequest请求(url);
QNetworkReply*reply=qnam->post(请求);
}
这是一个很好的实践,在C++一般处理指针由于简化的维护。然而,如果粘贴时有一个简单的代码,那么这可能是一个设计过度的解决方案。
希望这个冗长的解释有助于避免混淆