QT qDeleteAll and new afterwards same memory address and crash - c++

I have a weird behavior when using qDeleteAll on a QMap<QString, Record*>.
First I delete my values in the QMap with qDeleteAll and then I use m_data.clear()
to empty the QMap.
void ClassName::function1(QMap<QString, QString> filter)
{
qDebug() << "function1 called";
QString query = "postgrestAdress?";
if (filter.size()){
for (QMap<QString, QString>::iterator i = filter.begin(); i != filter.end(); i++ ) {
query.append("&").append(i.key()).append("=").append(i.value());
}
}
postgrestLambdaFucntion(query,[this, query](QList<QMap<QString,QString>> result)
{
qDeleteAll(m_data);
m_data.clear();
m_users.clear();
for(auto &line : result)
{
Record *record = Mapper::mapQMapToRecord(line);
qDebug() << "created Record:" << record << " with id:" << record->id;
m_data.insert(line.value("material_number")+ "_" +QString::number(record->id), record);
if (!m_users.contains(line.value("user"))){
m_users.append(line.value("user"));
}
}
nextFunction(0);
});
}
Consider this as a record:
class Record : public QObject
{
Q_OBJECT
public:
explicit Record(QObject *parent = nullptr) : QObject(parent){};
~Record() {
qDebug() << "record " << this << "with id" << this->id << " is destroyed";
};
int id = 0;
QString material_number = "";
QString user = "";
}
When I call function1 with an already populated m_data list I get this debug information:
>Returing table from postgrest...
>record Record(0x564813686040) with id 1 is destroyed
>record Record(0x5648136f74b0) with id 33 is destroyed
>record Record(0x56481376a6b0) with id 15 is destroyed
>record Record(0x564813708c00) with id 43 is destroyed
>record Record(0x564813c28090) with id 44 is destroyed
>record Record(0x564813768eb0) with id 2 is destroyed
>record Record(0x5648136eb7a0) with id 14 is destroyed
>created Record: Record(0x564813768eb0) with id: 15
>created Record: Record(0x564813c28090) with id: 2
>created Record: Record(0x564813708c00) with id: 43
>created Record: Record(0x56481376a6b0) with id: 33
>created Record: Record(0x5648136f74b0) with id: 14
>created Record: Record(0x564813686040) with id: 1
>created Record: Record(0x564813de45b0) with id: 44
Inside the Mapper-Function I create new Record-Classes
Record* Mapper::mapQMapToRecord(QMap<QString, QString> line)
{
Record* record = new Record(nullptr);
record->id = line.value("id").toInt();
record->user = line.value("user");
return record;
}
Note that the Memory-Address of those new created objects are the same
as the ones qDeleteAll removed.
In the next function I make more requests and add data to the records,
which are now "not available" and I get nullptr exceptions.
If I don't use "qDeleteAll" it works.
I can also use a for-loop and use "deleteLater" from QObject
without errors.
I just want to know this behaviour better or why it happens.
(it happens in debug and release builds)
Anybody has insights for me?
Best Regards
exa.byte

Related

Unable to print out generated list with SQL Database statements [Android Studio]

I have coded some code that connects to a databse in the internal storage of the device, runs a SQL statement to filter out excercises, then iterate through the results and create a list that can be used later in the program. However, the list returns nothing when checked with Log statements. I have checked whether the SQL statements work with log statements before the iteration and it returns correct row values.
package com.example.fit_world;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.content.res.AssetManager;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.util.Log;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import com.example.fit_world.Exercise;
public class GenerateWorkout extends AppCompatActivity {
private static final String DATABASE_NAME = "Exercises.db";
private SQLiteDatabase database;
private void copyDatabaseToInternalStorage() {
InputStream inputStream = null;
OutputStream outputStream = null;
try {
// Open the database file in the assets folder
AssetManager assetManager = getAssets();
inputStream = assetManager.open(DATABASE_NAME);
if (inputStream == null) {
throw new IOException("Failed to open file: " + DATABASE_NAME);
}
// Generate a unique file name for the database in the internal storage
File outputFile = new File(getFilesDir(), "Exercises_" + System.currentTimeMillis() + ".db");
// Check if the file already exists in the internal storage
if (outputFile.exists()) {
// Delete the file if it already exists
outputFile.delete();
}
outputStream = new FileOutputStream(outputFile);
// Copy the database file from the assets folder to the internal storage
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, length);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// Close the streams
try {
if (inputStream != null) {
inputStream.close();
}
if (outputStream != null) {
outputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_generate_workout);
String equipmentType = "None";
String difficultyType = "Easy";
String weightGoalType = "Weight Loss";
List<Exercise> exercises = getExercisesFromDatabase(equipmentType, difficultyType, weightGoalType);
for (Exercise exercise : exercises) {
Log.d("LOL", exercise.toString());
}
}
private List<Exercise> getExercisesFromDatabase(String equipmentType, String difficultyType, String weightGoalType) {
List<Exercise> exercises = new ArrayList<>();
// Check if the database file exists in the internal storage
File databaseFile = new File(getFilesDir(), DATABASE_NAME);
if (!databaseFile.exists()) {
// If the database file does not exist, copy it from the assets folder
copyDatabaseToInternalStorage();
}
// Open the database file in the internal storage
SQLiteDatabase database = null;
Cursor cursor = null;
try {
// Open the database file in the internal storage
database = openOrCreateDatabase("Exercises.db", MODE_PRIVATE, null);
// Execute the query to retrieve the list of exercises
String query = "SELECT * FROM Exercises WHERE Equipment = ? AND Difficulty = ? AND Goal = ?";
String[] selectionArgs = new String[]{equipmentType, difficultyType, weightGoalType};
cursor = database.rawQuery(query, selectionArgs);
int rowCount = cursor.getCount();
System.out.print(rowCount);
Log.d("TAG", "Row count: " + rowCount);
Log.d("MMM", "Row count: " + database.rawQuery("SELECT * FROM exercises", null).getCount());
// Iterate through the result set and create a list of exercises
while (cursor.moveToNext()) {
int idColumnIndex = cursor.getColumnIndex("id");
int nameColumnIndex = cursor.getColumnIndex("name");
int descriptionColumnIndex = cursor.getColumnIndex("description");
int equipmentColumnIndex = cursor.getColumnIndex("equipment");
int difficultyColumnIndex = cursor.getColumnIndex("difficulty");
int weightGoalColumnIndex = cursor.getColumnIndex("weight_goal");
int requiredEquipmentColumnIndex = cursor.getColumnIndex("required_equipment");
int numberOfRepsColumnIndex = cursor.getColumnIndex("number_of_reps");
if (idColumnIndex != -1 && nameColumnIndex != -1 && descriptionColumnIndex != -1 && equipmentColumnIndex != -1 &&
difficultyColumnIndex != -1 && weightGoalColumnIndex != -1 && requiredEquipmentColumnIndex != -1 &&
numberOfRepsColumnIndex != -1) {
int id = cursor.getInt(idColumnIndex);
String name = cursor.getString(nameColumnIndex);
String description = cursor.getString(descriptionColumnIndex);
String equipment = cursor.getString(equipmentColumnIndex);
String difficulty = cursor.getString(difficultyColumnIndex);
String weightGoal = cursor.getString(weightGoalColumnIndex);
String requiredEquipment = cursor.getString(requiredEquipmentColumnIndex);
int numberOfReps = cursor.getInt(numberOfRepsColumnIndex);
Exercise exercise = new Exercise(id, name, description, equipment, difficulty, weightGoal, requiredEquipment, numberOfReps);
exercises.add(exercise);
Log.d("TAG", "Exercise name: " + name);
Log.d("TAG", "Exercise description: " + description);
Log.d("TAG", "Exercise equipment: " + equipment);
Log.d("TAG", "Number of exercises retrieved: " + exercises.size());
}
}
} catch (SQLException e) {
e.printStackTrace();
Log.e("TAG", "Error accessing database: " + e.getMessage());
} finally {
// Close the cursor and database
if (cursor != null) {
cursor.close();
}
if (database != null) {
database.close();
}
}
return exercises;
}
}
I tried to use log statements in order to see the list of excercises that is printed however nothing gets printed to the logcat, the SQL statements work as I have used a log statement to see the values printed and that works fine
I suspect that when valid data exists that something does get printed out, but not what is expected and therefore perhaps missed.
More specifically what is printed depends upon the toString method of the Exercise class as is used by:-
for (Exercise exercise : exercises) {
Log.d("LOL", exercise.toString());
}
It may be something along the lines of D/LOL: a.a.so75035530javasqliteemptylist.Exercise#58c3a3e (this from an adaption of the code you have supplied)
Otherwise the core code appears to be fine. The following was the adaptated code used to test with some data (a single row) in the database that is opened (just one row):-
private List<Exercise> getExercisesFromDatabase(String equipmentType, String difficultyType, String weightGoalType) {
List<Exercise> exercises = new ArrayList<>();
// Check if the database file exists in the internal storage
/*
File databaseFile = new File(getFilesDir(), DATABASE_NAME);
if (!databaseFile.exists()) {
// If the database file does not exist, copy it from the assets folder
copyDatabaseToInternalStorage();
}
*/
// Open the database file in the internal storage
SQLiteDatabase database = null;
Cursor cursor = null;
try {
// Open the database file in the internal storage
//database = openOrCreateDatabase("Exercises.db", MODE_PRIVATE, null);
File dbfile = this.getDatabasePath(DATABASE_NAME);
database = SQLiteDatabase.openOrCreateDatabase(dbfile,null);
// Execute the query to retrieve the list of exercises
String query = "SELECT * FROM Exercises /*WHERE Equipment = ? AND Difficulty = ? AND weightGoal = ?*/";
String[] selectionArgs = new String[]{equipmentType, difficultyType, weightGoalType};
cursor = database.rawQuery(query, /*selectionArgs*/ new String[]{});
DatabaseUtils.dumpCursor(cursor);
int rowCount = cursor.getCount();
System.out.print(rowCount);
Log.d("TAG", "Row count: " + rowCount);
Log.d("MMM", "Row count: " + database.rawQuery("SELECT * FROM exercises", null).getCount());
// Iterate through the result set and create a list of exercises
while (cursor.moveToNext()) {
int idColumnIndex = cursor.getColumnIndex("id");
int nameColumnIndex = cursor.getColumnIndex("name");
int descriptionColumnIndex = cursor.getColumnIndex("description");
int equipmentColumnIndex = cursor.getColumnIndex("equipment");
int difficultyColumnIndex = cursor.getColumnIndex("difficulty");
int weightGoalColumnIndex = cursor.getColumnIndex("weightGoal");
int requiredEquipmentColumnIndex = cursor.getColumnIndex("requiredEquipment");
int numberOfRepsColumnIndex = cursor.getColumnIndex("numberOfReps");
if (1 == 1 /*idColumnIndex != -1 && nameColumnIndex != -1 && descriptionColumnIndex != -1 && equipmentColumnIndex != -1 &&
difficultyColumnIndex != -1 && weightGoalColumnIndex != -1 && requiredEquipmentColumnIndex != -1 &&
numberOfRepsColumnIndex != -1*/) {
int id = cursor.getInt(idColumnIndex);
String name = cursor.getString(nameColumnIndex);
String description = cursor.getString(descriptionColumnIndex);
String equipment = cursor.getString(equipmentColumnIndex);
String difficulty = cursor.getString(difficultyColumnIndex);
String weightGoal = cursor.getString(weightGoalColumnIndex);
String requiredEquipment = cursor.getString(requiredEquipmentColumnIndex);
int numberOfReps = cursor.getInt(numberOfRepsColumnIndex);
Exercise exercise = new Exercise(id, name, description, equipment, difficulty, weightGoal, requiredEquipment, numberOfReps);
exercises.add(exercise);
Log.d("TAG", "Exercise name: " + name);
Log.d("TAG", "Exercise description: " + description);
Log.d("TAG", "Exercise equipment: " + equipment);
Log.d("TAG", "Number of exercises retrieved: " + exercises.size());
}
}
} catch (SQLException e) {
e.printStackTrace();
Log.e("TAG", "Error accessing database: " + e.getMessage());
} finally {
// Close the cursor and database
if (cursor != null) {
cursor.close();
}
if (database != null) {
database.close();
}
}
return exercises;
}
As can be seen rather than test using an asset etc, the database is in the standard location, it being created and populated in the initial (MainActivity) which is
:-
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this,GenerateWorkout.class);
frigDatabase();
startActivity(intent);
}
void frigDatabase() {
SQLiteDatabase db;
String dbname = GenerateWorkout.DATABASE_NAME;
File dbfile = this.getDatabasePath(dbname);
boolean exists = dbfile.exists();
db = SQLiteDatabase.openOrCreateDatabase(dbfile,null);
if (!exists) {
db.execSQL("CREATE TABLE exercises (" +
"id INTEGER PRIMARY KEY," +
"name TEXT," +
"description TEXT," +
"equipment TEXT," +
"difficulty TEXT," +
"weightGoal TEXT," +
"requiredEquipment TEXT," +
"numberOfReps INTEGER DEFAULT 10" +
");"
);
ContentValues cv = new ContentValues();
cv.put("name","fred");
cv.put("description","d1");
cv.put("equipment","E1");
cv.put("difficulty","hard");
cv.put("weightGoal","10kg");
cv.put("requiredEquipment","ALL");
db.insert("exercises",null,cv);
}
}
}
other changes made were to select the one and only row (and to use column names based upon the Exercise class (note that getColumnIndex is case dependent)).
you may also notice the use of the DatabaseUtils dumpCursor method with this then the resultant output used to test was
:-
2023-01-07 09:34:55.792 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor#67e09f
2023-01-07 09:34:55.792 I/System.out: 0 {
2023-01-07 09:34:55.793 I/System.out: id=1
2023-01-07 09:34:55.793 I/System.out: name=fred
2023-01-07 09:34:55.793 I/System.out: description=d1
2023-01-07 09:34:55.793 I/System.out: equipment=E1
2023-01-07 09:34:55.793 I/System.out: difficulty=hard
2023-01-07 09:34:55.793 I/System.out: weightGoal=10kg
2023-01-07 09:34:55.793 I/System.out: requiredEquipment=ALL
2023-01-07 09:34:55.793 I/System.out: numberOfReps=10
2023-01-07 09:34:55.793 I/System.out: }
2023-01-07 09:34:55.793 I/System.out: <<<<<
2023-01-07 09:34:55.793 D/TAG: Row count: 1
2023-01-07 09:34:55.794 D/MMM: Row count: 1
2023-01-07 09:34:55.795 D/TAG: Exercise name: fred
2023-01-07 09:34:55.795 D/TAG: Exercise description: d1
2023-01-07 09:34:55.795 D/TAG: Exercise equipment: E1
2023-01-07 09:34:55.795 D/TAG: Number of exercises retrieved: 1
2023-01-07 09:34:55.802 D/LOL: a.a.so75035530javasqliteemptylist.Exercise#ca545ec
As you can see the output/results are consistent with the expectation BUT the very last line is what is obtained from the loop through the returned List and thus probably not what was expected.
However if the following were used:-
List<Exercise> exercises = getExercisesFromDatabase(equipmentType, difficultyType, weightGoalType);
for (Exercise exercise : exercises) {
Log.d("LOL", exercise.toString());
Log.d("LOL_","Name is " + exercise.name + " Description is " + exercise.description + " etc."); /*<<<<<<<<<< ADDED >>>>>>>>>>*/
}
Then the output is would be more recognisable:-
2023-01-07 09:51:07.442 D/LOL: a.a.so75035530javasqliteemptylist.Exercise#ca545ec
2023-01-07 09:51:07.442 D/LOL_: Name is fred Description is d1 etc.
Additional
As you say that the dumpCursor does extract the expected data. Then the most likely issue is that at least one of the ??columnIndex index values is looking for a column that is not in the cursor and is hence -1 and thus will not satisfy the if statement (if (idColumnIndex != -1 && nameColumnIndex != ....) (check the dumpCursor output is tells you the actual column names)
Adding a breakpoint on the first attempt to get a value from the cursor in the body of the if (note that the IF clause has been changed to always be true to allow debug to enter the body) and running in debug mode. This would allow you to see what is what. The following is an example that shows the breakpoint (red dot placed by clicking the line number) and the result of running the App in debug mode (Shift F9) :-
As can be ascertained weightGaolIndex is -1 and thus that the column name, as per the line int weightGoalColumnIndex = cursor.getColumnIndex("Goal"); (note Goal purposefully used to produce the -1(. Using debug to expand cursor and then to expand mColumnNameMap shows:-
i.e. the column name in the Cursor is weigthGoal NOT Goal
You should also note that the getColumnIndex method is case sensitive so the case of the name being searched MUST match the case of the column in the cursor.

How to create an object in C++/Qt?

void MainWindow::on_actionformattedActivity_triggered()
{
// todo: Button=> file reading
Activity* act = new Activity("name",0,1,40,20,true,actNum);
qDebug() << "actNum" <<actNum;
activities.append(*act) ;
qDebug()<< "list element";
foreach (Activity a, activities) {
//qDebug() << a.actListWidgetItem->text();
qDebug() << a.actIsVisible;
qDebug() << a.actID;
}
qDebug()<< "list size";
qDebug()<<activities.size();
//timeline->AddTimeLineElement(act->ActStartingPoint() , act->ActRect(), penBlack, brushBlue);
// ui->listWidgetActivities->addItem(act->actListWidgetItem);
actNum++;
}
Activity Constructor
Activity::Activity(QString name, int err, int war,int startTime,int length, bool isVisible,int numberID)
{
// QListWidgetItem* actListItemWidget = new QListWidgetItem();
// actListItemWidget->setText(name + "___" + QString::number(err) + "___" + QString::number(war));
//QPointF* actStartingPoint = new QPointF((numberID -1) * rectHeight, startTime );
//QRect* actRect = new QRect (0,0,length,rectHeight);
bool actIsVisible = isVisible;
int actID = numberID;
}
I want to create an object from the class Activities which contains a bunch of data I need to display. whenever I click the button that call this function the system crashes. I decided to check the content of the
QList activities
the output show the correct actNum and List size but random values...
actNum 0
list element
true
0
list size
1
actNum 1
list element
true
0
true
0
list size
2
How can I create and access an object from Activity class?

How to declare an empty rowset properly with SOCI?

Imagine that I have the following function. In case of invalid parameters or exception, the function has to exit with an empty rowset.
rowset<row> SelectAllFromTable(string tableName)
{
session sql(odbc, "...");
// if parameters are not valid -> return empty rowset<row>
if (tableName == "")
{
// query that returns 0 result
rowset<row> res = (sql.prepare << "SELECT ID FROM T1 WHERE ID = -9999");
return res;
}
string query = "SELECT * FROM " + tableName;
try
{
rowset<row> rs = sql.prepare << query;
return rs;
}
catch (exception const &e)
{
cerr << "Error: " << e.what() << endl;
// query that returns 0 result
rowset<row> res = (sql.prepare << "SELECT ID FROM T1 WHERE ID = -9999");
return res;
}
// query that returns 0 result
rowset<row> res = (sql.prepare << "SELECT ID FROM T1 WHERE ID = -9999");
return res;
}
The solution I wrote above works but my question is : Is there a better way to return an empty rowset with SOCI ?
Since the documentation hasn't much to offer to this I looked into the rowset Header: There is no default constructor for it and no public method to set the iterators, ergo you can't get an empty rowset by yourself.
Despite why don't you use exceptions which are just perfect for that case. Just don't catch the soci_error exception, then the caller SelectAllFromTable could catch it. This would have many advantages:
The caller would know if there is really no data in the table or there is no table
The caller could know why he can't use the table (misspelled or security reasons)
The caller could know if there are other troubles and take action or if not, rethrow it, so his caller might can.

Memory management in C++?

I'm developing a simple vehicle routing problem algorithm and I have a little problem with memory management. So I have following classes
In this one I store data of an Order
Order::Order(int id, int idLoc, double xCoord, double yCoord, double demand, int startTime, int endTime, int serviceTime) {
this->id = id;
this->idLoc = idLoc;
this->xCoord = xCoord;
this->yCoord = yCoord;
this->demand = demand;
this->startTime = startTime;
this->endTime = endTime;
this->serviceTime = serviceTime;
}
Order::~Order() {
// TODO Auto-generated destructor stub
}
In this one I store a list of Orders which represent a sequence of customers to serve during the distribution.
Route::Route(int idRoute,Vehicle *vehicleRoute) {
id = idRoute;
vehicle = vehicleRoute;
demandRoute = -1;
serviceTimeRoute =-1;
earliestTimeRoute =-1;
latestTimeRoute = -1;
serviceDistanceRoute = -1;
orders = new std::deque<Order>;
}
Route::Route(int idRoute, std::deque<Vehicle>::iterator vehicleIterator) {
id = idRoute;
vehicle = &(*vehicleIterator);
demandRoute = -1;
serviceTimeRoute =-1;
earliestTimeRoute =-1;
latestTimeRoute = -1;
serviceDistanceRoute = -1;
orders = new std::deque<Order>;
}
Route::~Route() {
std::cout << "Destroying Route " << id << std::endl;
delete orders;
std::cout << "Route Destroyed" << std::endl;
}
Finally, here I store a set of routes.
Solution::Solution() {
solution = new std::deque<Route>;
}
Solution::~Solution() {
std::cout << "Destroying Solution" << std::endl;
delete solution;
std::cout << "Solution Destroyed" << std::endl;
}
The problem is here:
readCustomers(&orderList, &depotList);
readVehicles(&vehicleList);
std::deque<Vehicle>::iterator it = vehicleList.getVehicleList()->begin();
int routeID = 0;
Route route (routeID, it);
solution.getSolution()->push_back(route); //Problem
So I read Orders and Vehicles then I create Route route which has no Orders associated yet and finally I add this route to a solution.
When I compile this code I got following output:
Route address: 0x7fff7351e110
Solution's route address: 0x1ab8270
Destroying Route 0
Route Destroyed
Destroying Solution
Destroying Route 0
Route Destroyed
Solution Destroyed
*** Error in `/home/.../': corrupted double-linked list: 0x0000000001ab5800 ***
Used valgrind to gather more information about this error, got folowing messages:
IVR [1]: Invalid read of size 8
IVF [1]: Invalid free()/delete/delete[]/realloc()
I guess I am releasing same chunk of memory twice. But I don't see where.
Can any one help me with this one.
Route objects get copied when used in a std::deque.
I see no Copy operator and you allocate the orders with new. When a Route is now copied, the pointer is copied too. So you have two objects pointing to the same object and freeing the same memory.
Why are you using new and delete here. Embed the std::deque directly as a member and avoid new/delete.
If you need new/delete:
Try to use smart pointers
Implement a copy constructor and copy operator.
If you decide to add it as a member you need to declare it in the class:
class Route ...
{
...
std::deque<Order> orders;
There is no need for new delete at all.

Qt: QScriptValueIterator has an extra element

I am trying to read JSON objects using the QScriptValue class in Qt and I've noticed that when iterating over an array I always get an extra element at the end.
Let's say I have a string named value like this:
QString value = "{\"identifier\":\"testID\",
\"params\":[{\"field\":\"filed1:\",
\"datatype\":\"integer\",\"fieldend\":\" \"},{\"field\":\"field2:
\",\"datatype\":\"integer\",\"fieldend\":\" \"}]}";
My code for iteration looks like this:
QScriptValue sc;
QScriptEngine engine;
sc = engine.evaluate("("+value+")");
if(sc.isValid())
{
if(sc.property("params").isArray())
{
QScriptValueIterator it(sc.property("params"));
while(it.hasNext())
{
it.next();
qDebug()<< "field:" << it.value().property("field").toString();
qDebug()<< "datatype:" << it.value().property("datatype").toString();
qDebug()<< "fieldend:" << it.value().property("fieldend").toString();
qDebug()<< "--------------";
}
}
}
The output results with an extra element that has empty values:
field: "field1:"
datatype: "integer"
fieldend: " "
--------------
field: "field2: "
datatype: "integer"
fieldend: " "
--------------
field: ""
datatype: ""
fieldend: ""
--------------
I read the documentation of QScriptValueIterator and it says:
The next() advances the iterator. The name(), value() and flags() functions return the name, value and flags of the last item that was
jumped over
So I changed my iteration accordingly:
while(it.hasNext())
{
it.next();
qDebug() << it.name() << " : " << it.value().toString();
qDebug()<< "--------------";
}
But I get something that I did not expect:
"0" : "[object Object]"
--------------
"1" : "[object Object]"
--------------
"length" : "2"
--------------
Can anyone point out what am I doing wrong here?
Thanks.
I faced the same issue and I added this line after the it.next(); line:
if (it.flags() & QScriptValue::SkipInEnumeration) continue;
You can find more info about it here:
http://developer.qt.nokia.com/doc/qt-4.8/qscriptvalueiterator.html#details