PDA

View Full Version : Crash on QString assignment



ce_nort
23rd March 2016, 21:11
I'm pretty new to Qt and C++ so I'm probably missing something obvious, but for the life of me I can't figure out what is going wrong. One of the classes in a program I wrote is causing a crash whenever I try to do a basic string assignment. See below (slightly pared down).


class AutochargeData : public QWidget
{

public:
AutochargeData(appData *appInfo, QWidget *parent = 0);

QString orderNum;
QString paymentMethod;
QString total;

void setPayment(QString payment);
void setOrderID(QString orderID);
void setTotal(QString total);

void getPaymentData(QString orderID);

private:
appData *appInfo;

};

So in the below code, I have tried many variations. I know the query is fine because I've used qDebug() to check the output. I have tried skipping the set functions and doing a direct assignment, I have tried using the "this" keyword, and I have even tried just assigning a random string directly to the variables.


AutochargeData::AutochargeData(appData *appInfo, QWidget *parent) :
QWidget(parent)
{
this->appInfo = appInfo;
}

void AutochargeData::getPaymentData(QString orderID)
{
QString queryString = "SELECT order_payment.method, order.increment_id, order.grand_total FROM order JOIN order_payment ON sales_flat_order.entity_id = order_payment.parent_id WHERE order.increment_id = '" + orderID + "';";

QSqlQuery query(queryString, QSqlDatabase::database("db"));
query.exec();

while (query.next()) {
setOrderID(query.value("increment_id").toString());
setPayment(query.value("method").toString());
setTotal(query.value("grand_total").toString());
}
}

void AutochargeData::setPayment(QString payment)
{
paymentMethod = payment;
}

void AutochargeData::setOrderID(QString orderID)
{
orderNum = orderID;
}

void AutochargeData::setTotal(QString grandTotal)
{
total = grandTotal;
}

Any time I tried to assign a string to the orderNum, paymentMethod, or total variables, the program crashes. The debugger is ending on
QString::operator=(const char*) in the qstring.h file. As I mentioned, I am relatively new at this so it may be something obvious that I am missing. But after multiple hours of googling and trying different variations, I am stumped. Any thoughts would be much appreciated, and please let me know if there's more information that would be helpful.

anda_skoa
23rd March 2016, 22:18
That usually means that "this" is not a valid object.
I.e. that you are calling a method on a pointer that does not actual point to a valid object.

E.g. an uninitialized pointer or a deleted pointer.

Cheers,
_

d_stranz
24th March 2016, 15:34
I would look at the lifetime of the "appData" pointer. You are simply storing it in your AutochargeData class. If it goes out of scope (e.g. is deleted) before the AutochargeData class instance does, then it is an invalid pointer and if used will cause a crash.


while (query.next()) {
setOrderID(query.value("increment_id").toString());
setPayment(query.value("method").toString());
setTotal(query.value("grand_total").toString());
}

This code makes no sense. If the query result has more than one result in it, each time through the loop you are completely replacing the values in your member variables (which themselves should not be public members of the class). At the end of the loop they will simply contain the values from the last result. I don't imagine that is your intent.

Also not really sure why you have derived AutochargeData from QWidget. It doesn't appear to have any user interface, so why? Deriving from QWidget (or QObject for that matter) is unnecessary for pure C++ classes used in a Qt application. If you do derive from a QObject-based class (like QWidget), then you need to include the "Q_OBJECT" macro at the top of the class definition:


class MyClass : public QObject
{
Q_OBJECT

public:
MyClass( QObject * parent );

...
}

ce_nort
25th March 2016, 14:51
Thanks for all the info, I am definitely new at this and self-taught/teaching so it is very helpful. I actually do have the "Q_OBJECT" macro in at the top of the class definition, I just left it out of the copy and paste. I'm not using signals and slots in this class, but I generally add it by default (bad idea?). I agree that the while loop would make no sense if the query returned more than one set of values, but it does not. There should be only one set of data to assign to the member variables, and the while loop was my understanding of how to check that the query returned successfully. I certainly don't claim that this is well written - I'm still learning what that looks like. It sounds like the general consensus is that the appData pointer is the issue and is probably deleted too soon elsewhere in the program. I'll check it out! Thanks again.

Radek
25th March 2016, 16:05
IMO, the problem isn't in Q_OBJECT (as long as AutochargeData does not use "Qt extras" - it is not an UI object, it declares no properties, slots or signals, etc.) The setOrderID() method is innocent. IMO, the problem is somewhere in the database. For starters, I recommend splitting the setOrderID() statement and seeing whether you pass and what values will the debugger show. Therefore:


QVariant val = query.value("increment_id"); // does it pass?
QString str = val.toString(); // does it pass? What is in str?

setOrderID(str); // does it pass? What happens?

Pleas, post your findings.

ce_nort
25th March 2016, 16:08
I got this figured out shortly before you posted. As predicted, it was something obvious that I was missing. I had created an instance of AutochargeData in the Mainwindow class, but was trying to use it in a different class without creating another instance of it. So it was invalid, as was guessed by the other posts in this thread. Thanks everyone!