0

I've created a custom QLineEdit widget that handles drag and drop of files. Everything is working great with that part, but as soon as I add a Class variable the application crashes either at the construction of the class or at destruction:

  • When my variable is QString, it crashes at construction
  • When my variable is QString*, it crashed at destruction

I tried deleting the variable (QString*) in the destructor, same issue...

Any ideas?

Header:

#ifndef DROPLINEEDIT_H
#define DROPLINEEDIT_H

#include <QLineEdit>
#include <QDragEnterEvent>
#include <QMimeData>
#include <QFileInfo>
#include <QString>
#include <QDebug>


class DropLineEdit : public QLineEdit
{
    Q_OBJECT
public:
    explicit DropLineEdit(QWidget *parent = 0);
    ~DropLineEdit();

protected:
    virtual void dragEnterEvent(QDragEnterEvent *event);
    virtual void dropEvent(QDropEvent *event);
    virtual void dragLeaveEvent(QDragLeaveEvent *event);

signals:

public slots:

private:

    QString * mFileName;

};

#endif // DROPLINEEDIT_H

Source:

#include "droplineedit.h"

DropLineEdit::DropLineEdit(QWidget *parent) :
    QLineEdit(parent)
{
    setAcceptDrops(true);
    this->setReadOnly(true);
    this->setStyleSheet("QLineEdit { border: 2px solid gray ; border-radius: 8px ; padding: 0 6px }");
}

DropLineEdit::~DropLineEdit()
{
    if(!mFileName){
        delete mFileName;
    }
}

// **************************************** PROTECTED METHODS **************************************** //

void DropLineEdit::dragEnterEvent(QDragEnterEvent *event){
    this->setStyleSheet("QLineEdit { border: 3px solid black ; border-radius: 8px ; padding: 0 6px }");
    event->accept();
}
void DropLineEdit::dragLeaveEvent(QDragLeaveEvent *event){
    this->setStyleSheet("QLineEdit { border: 2px solid gray ; border-radius: 8px ; padding: 0 6px }");
    event->accept();
}

void DropLineEdit::dropEvent(QDropEvent *event){
    // Get the data. If multiple files are dropped, take only the first one and fetch save its info
    QList<QUrl> list = event->mimeData()->urls();
    QFileInfo * fileInfo = new QFileInfo(list.at(0).toLocalFile());

    qDebug() << fileInfo->absoluteFilePath();
    mFileName = new QString(fileInfo->absoluteFilePath());

    this->setText(fileInfo->fileName());
    this->setStyleSheet("QLineEdit { border: 2px solid gray ; border-radius: 8px ; padding: 0 6px }");
    event->accept();
}
speed488
  • 302
  • 1
  • 10
  • i suggest you set mFileName(NULL) in the initializer list (i.e. in your constructor) - **QLineEdit(parent), mFileName(NULL)** – Son-Huy Pham Jun 28 '13 at 21:08
  • 1
    Don't use pointers when it's not necessary. `QFileInfo fileInfo(list.at(0).toLocalFile())`. And check that the list is not empty before doing that: `if(!list.isEmpty())`. Same with your QString, don't make it a pointer. `mFileName = fileInfo.absoluteFilePath();` – thuga Jun 29 '13 at 12:47

2 Answers2

2

Add this to the constructor:

mFileName = 0;

You need to initialize the pointer. Otherwise it will have random value and you will be unable to check if you have created an object.

Modify the destructor:

delete mFileName;

You need to delete object if it's not NULL (your version is the opposite). delete will perform the check internally.

Note that if mFileName = new QString... is executed multiple times, several objects will be created. You need to delete previous object before creating new one if you need to avoid memory leak.

However, all the above information is provided for general education. You should not use QString* here. Non-pointer QString class member will be much more correct. In this case you don't need to use new or delete, you don't need to care about pointers and memory at all.

Pavel Strakhov
  • 39,123
  • 5
  • 88
  • 127
  • I just tried this solution (inverting the logic in the destruction and forcing 0 to the pointer at construction) and I get the same issue. As for the QString (non pointer), it was my first choice, but it crashes the app at the construction of the object. – speed488 Jun 28 '13 at 21:33
  • 2
    To be really pedantic: `if (x) delete x;` is exactly the same as `delete x;`, just way more verbose. – peppe Jun 28 '13 at 21:52
  • @speed488 run it through a debugger – Son-Huy Pham Jun 28 '13 at 22:14
  • I'd take it one step further: he doesn't even need the QString at all. It's never read from, and is identical to the value returned by `QLabel::text()` anyways. – cgmb Jun 28 '13 at 23:46
  • I can't tell what is the issue with non-pointer QString because you didn't provide the code. I can only tell about issues in the posted code. And you need to use a debugger to localize the error. – Pavel Strakhov Jun 29 '13 at 06:32
  • You didn't initialize the member in the ctor. Then deleting it will crash unless it's properly initialized in dropEvent (which might or might not be called). – Frank Osterfeld Jun 29 '13 at 10:48
2

I was getting this as an error in debug: "invalid address specified to rtlfreeheap"

I did some research on that and found out that it could be related to an internal issue with Qt (the way object constructors are called). I went back in my main application to see how I called my DropLineEdit object and notice that I forgot to remove the setAcceptDrops(true) after creating DropLineEdit Classe (the object was formerly a normal QLineEdit before I created DropLineEdit).

Here was the function call:

DropLineEdit* Instrument::createDropLineEdit(){
    DropLineEdit * lineEdit = new DropLineEdit();
    lineEdit->setAcceptDrops(true);
    return lineEdit;
}

Changed to:

DropLineEdit* Instrument::createDropLineEdit(){
    DropLineEdit * lineEdit = new DropLineEdit();
    return lineEdit;
}

After removing that redundant call (redundant since the acceptdrops was set in the constructor), I didn't get any application crash either with QString or QString* as member variable of DropLineEdit Class. I used a QString (not the pointer) and I was able to make my Class do what is was supposed to.

Thanks for your replies guys. Much appreciated.

speed488
  • 302
  • 1
  • 10