I'm programming an application that uses QUdpSockets.
As I'm getting memory problems due to creating sockets with the operator new I would like to know if it is necesary to delete them after closing it.
Code below:
socket = new QUdpSocket(this);
socket->bind();
connect(socket, SIGNAL(readyRead()), this, SLOT(getResponse()));
socket->close();
delete socket; //Do I have to do this to free the mem?
Help will be thanked.
Depends on what this is. Whenever that gets destroyed, the QUdpSocket will be too.
As soon as you don't need the socket anymore you can call :
socket->deleteLater();
And yes, it's better to destroy the socket when you don't need it anymore.
An other solution is to delete 'this', so socket will be also deleted.
If your done with the socket you should delete it. This way you are on the safe side. Also it doesnt hurt. However as it was already pointed out "this" will take for the destruction of the socket (see http://doc.qt.io/qt-4.8/qobject.html#QObject ).
Related
I have this code:
QNetworkAccessManager man;
QNetworkRequest req(QUrl("URL"));
QString ua("HttpRequestDemo/0.1 (Win64) Qt/5.14.0");
req.setHeader(QNetworkRequest::UserAgentHeader, QVariant(ua));
QNetworkReply* reply = man.get(req);
QObject::connect(reply){
QByteArray read = reply->readLine();
QFile out("file.txt");
out.open(QIODevice::WriteOnly|QIODevice::Text);
out.write(read);
out.close();
})
This works on the main.cpp file, using the QCoreApplication, but I want to use the QApplication and download a specific data while pressing a button.
I put the same code on the on_pushButton_clicked() in the mainwindow.cpp file and it didn't even generate the file from the url.
The problem is that man and req go out of scope and are destroyed as soon as your on_pushButton_clicked() function returns, at which point the request probably hasn't even been sent yet.
You need to make sure that these objects outlive the current scope, either by making them members of the window class, or by allocating them on the heap and setting some QObject (maybe also the window class) as the parent.
The problem is that if you put the same code in a method like X you make QNetworkAccessManager a local variable that will be removed instantly that the connection is asynchronous. The solution is to make QNetworkAccessManager an attribute of the class.
*.h
private:
QNetworkAccessManager man;
*.cpp
void Klass::on_pushButton_clicked(){
QNetworkRequest req(QUrl("URL"));
QString ua("HttpRequestDemo/0.1 (Win64) Qt/5.14.2");
req.setHeader(QNetworkRequest::UserAgentHeader, QVariant(ua));
QNetworkReply* reply = man.get(req);
connect(reply, &QNetworkReply::finished, [&]() {
QByteArray read = reply->readAll();
QFile out("file.txt");
out.open(QIODevice::WriteOnly|QIODevice::Text);
out.write(read);
out.close();
reply->close();
reply->deleteLater();
})
}
If you are planning on potentially queuing very many downloads, I strongly recommend using libcurl in your Qt app. I was using QNetworkAccessManager to down 100+ financial quote files, and it would fail downloading ~ 1/3 of the time, and take a while to download. I switched to libcurl, and after figuring out how to get my crypto root certificates setup for https, it runs much faster, and almost never fails. I run it as a dll.
And yes, you will need to make sure the network manager, whether QNetworkManager or curl, doesn't go out of scope upon exiting the button handler. A more conventional pattern, although not necessarily better, is to either have a pointer to e.g. QNetworkManager in your parent class, and new it, or use a std::unique_ptr and std::make_unique (purportedly safer). Creating large objects on the stack can cause problems (in the old days, dare I say, stack overflows), and so is usually done on the heap. In this case, it's not very big, so it doesn't really matter. Alternatively, a form creating big objects might itself be created on the heap.
I try to use QTcpSserver, which would keep connection with one and only one client at a time, until the client disconnects. So, I keep the client with a member pointer in my class.
The problem arises here: In the examples I see on the internet, after disconnected(), it is called deleteLater(). Good, but I would use this class-member pointer again for another connection. Remember that the server keeps one and only one client at a time. So, what if the socket object is deleted after another connection assigned on it?
What I mean is:
class TcpServer(QObject* o) : public QTcpServer {
...
private:
QTcpSocket* client;
}
void TcpServer::connected() {
client = this->nextPendingConnection();
this->pauseAccepting();
connect(client, SIGNAL(disconnected()), client, SLOT(clientDisconnected()));
}
void TcpServer::clientDisconnected() {
client->deleteLater();
this->resumeAccepting();
}
Scenario is this:
Client connected. So, client = nextPendingConnection();
Server paused listening. Does not accept new connection.
Client is disconnected. client needs to be released. So, client->deleteLater() is calleed.
Server continues listening.
New connection comes. So, I need to client = nextPendingConnection();
But, previous client object was deleted? Maybe? Maybe not? What if event loop tries to delete client, after I have assigned the new connection to it in step 5?
So, how would I keep one and only one client, while deleting previous disconnected ones?
Would it be safe if I do this?
void TcpServer::clientDisconnected()
{
QSocket* ptr = client;
ptr->deleteLater();
...
}
I will cite Qt documentation about it:
The object will be deleted when control returns to the event loop.
So deleteLater() is a delayed delete. The object is to be regarded as deleted as soon as the call deleteLater() was made.
Your nextPendingConnection() call will create another object that need to be deleted some time later.
However in your case you only allow one pending connection as you said and disallow accepting until client gets disconnected. I this case it should be safe, in other cases you could overwrite your client pointer and will lose control over it (memory leak).
Even in your case, I would prefer this solution:
void TcpServer::clientDisconnected()
{
if (qobject_cast<QAbstractSocket*>(sender())) {
sender()->deleteLater();
}
...
}
This would also be safe if more than one connection is allowed in future changes of your application.
As i understand nextPendingConnection(); will return pointer to new QTcpSocket class object so you have nothing to worry about.
deleteLater() will scheduled for deletion only your old object. QTcpSocket* client contains only pointer to QTcpSocket class object. When you calling deleteLater() Qt will delete only object to which client was pointed at time of calling this function.
i have a tcp server, which requires to allow exactly one client to connect to it at any time. anytime a new client connects, older session must be deleted and new session created.
right now, i am doing it like this:
void TcpServer::start_accept() {
Logger::info("[TCPSERVER] TCP Server starting to accept", __LINE__, __FILE__);
if (session) { // check if there is any older session, if so..delete them
session = NULL;
delete session;
}
session = new TcpServerSession(io_service_);
acceptor_.async_accept(session->socket(), boost::bind(&TcpServer::handle_accept, this, session, boost::asio::placeholders::error));
}
so any time i would like to send a msg to the client, it is being done like this:
int TcpServer::sendMsgToClient(std::string msg) {
if (session)
session->sendMsgToClient(msg);
}
i am wondering if this is being done correctly? basically the main point is deleting a pointer and re-creating it.whats the best way to do this?
Just use a std::unique_ptr<> :
session.reset(new TcpServerSession(io_service_));
It gets everything right: don't delete old object before a new one is available, never have session point to something invalid, and even in the presence of exceptions no memory is leaked.
if (session) { // check if there is any older session, if so..delete them
session = NULL;
delete session;
}
This is totally wrong! You blank out session, leaking whatever is currently there, and then delete NULL, which does absolutely nothing.
To be exception safe, you should not delete the old session until you have successfully created the new one. Something like this:
if (session) {
// Create and initialise the new session first
TcpServerSession* newSession = new TcpServerSession(io_service_);
// Don't know what this line does, but I assume it's important
acceptor_.async_accept(newSession->socket(), boost::bind(&TcpServer::handle_accept, this, newSession, boost::asio::placeholders::error));
std::swap(session, newSession); // Put the new one in place
delete newSession; // delete the old one.
}
Actually, this assumes async_accept doesn't throw. If it can, you will need to be careful to delete the newSession, probably with some kind of smart pointer.
session = NULL;
delete session;
Is most certainly not correct. If you replace the value that session holds (which points to a block of memory allocated by new) before calling delete on it, you effectively lose that block of memory, causing a memory leak. The only reason why this code doesn't blow up is because calling delete with a NULL is guaranteed to be a no-op.
Thus, you should replace the code with the following :
delete session;
session = NULL; // or nullptr if you've got C++11
Which will guarantee that the memory is properly freed.
Get rid of session = NULL before delete session. You're trying to delete the null pointer.
You don't need to set it to null because you're immediately going to set it to the new TCP session.
if (session) { // check if there is any older session, if so..delete them
session = NULL;
delete session;
}
This code says:
If session points to some valid object (instead of being null), then stop pointing to it (instead, point to NULL), and then delete what session now points to, i.e. delete nothing.
This is very bad. It is a genuine memory leak.
The comment is a lie.
I've connecting other process with socket connecting. So I create client socket which is object of CSocket Class. And I call Create method in CSocket class and I make my own program. But It doesn't work in create. It returns 0 value. Please tell me why does this happens.
Here's my brief code
CSocket *socket = new CSocket();
if(socket->Create())
if(socket->Connect("127.0.0.1",0))
socket->Send(widthCap, sizeof(widthCap));
socket->Close();
Thank you
Call GetLastError() and look the value up here. I would guess that you have a firewall that blocks your exe. Remember that adding your exe to your firewall exception list will not help as you probably build a new exe every time you hit F5.
I'm writing a tcp based server using Qt.
I plan this server to be multithreaded,
so my tcpserver class inherits from QTcpServer and overrides incomingConnection(). Everything is fine, except when it comes to deleting a user.
The TcpServer class manages
a list of QSharedPointer<Client>. When I remove the said client from the list, it gets automatically deleted because of the smart pointer.
My Client class owns a QSharedPointer<QTcpSocket> which means that the client's
QTcpSocket gets deleted when the client is deleted.
Problem is, it seems that Qt tries to use this socket after its deletion, causing Segmentation Fault.
Should I manages a list for the sockets only, and call deleteLater() on them when I dont need them anymore?
Or should I switch my socket's pointer in client class to a normal pointer?
void SlotSocketError(void)
{
QTcpSocket sock = qobject_cast<QTcpSocket *>(QObject::sender());
QSharedPointer<Client> client = GetClientFromSocket(sock);
_clientList.removeAt(GetClientPositionInList(client));
}
QList<QSharedPointer<Client> > _clientsList; // From TcpServer header.
/* Client's class header */
QSharedPointer<QTcpSocket> _socket;
You need to use deleteLater on the Object. Incoming messages may come in after you delete the QTCPSocket. It is documented in Assistant. You can find an example here: qthelp://com.trolltech.qt.472/qdoc/qt4-network.html
M
When you create your QSharedPointers you can pass a deleter to them, so that they'll use deleteLater instead of delete when you remove them from the list.
There is an example that does exactly that in the documentation too:
http://doc.trolltech.com/latest/qsharedpointer.html#QSharedPointer-3