maemo.org - Talk

maemo.org - Talk (https://talk.maemo.org/index.php)
-   Development (https://talk.maemo.org/forumdisplay.php?f=13)
-   -   QDataStream ad QList problem! (https://talk.maemo.org/showthread.php?t=55082)

saxen 2010-06-03 21:33

QDataStream ad QList problem!
 
hi there!
i'm working with qt nokia sdk and i'm blocked with a strange issue with list serialization!
I've a QList of objects called Service(pointer of Service, QList<Service*>), and i've to store it in a QSetting file using a QDataStream. I've already overloaded << and >> operator for Service objects and they work well.
Now i'm trying to save all the list, but:

Quote:

error: no match for ‘operator>>’ in ‘data >> ((MainList*)this)->MainList::services’
the strange thing is that << seems to work with QList<Service*>!

here some snap of my code:

Code:

#ifndef SERVICE_H
#define SERVICE_H
#include <QString>
#include "qmetatype.h"

class Service
{
public:
    Service();
    Service(QString name, QString address, bool needU, QString user,
            bool needP, QString password, bool needN, QString nick, bool active);
    QString getName();
    QString getAddress();
    QString getUser();
    QString getPassword();
    QString getNick();
    ..........
    bool isActive();
    bool needUser();
    bool needPass();
    bool needNick();

private:
    QString name;
    QString address;
    QString user;
    QString password;
    QString nick;
    bool active;
    bool needU;
    bool needP;
    bool needN;
};
QDataStream &operator<<(QDataStream &out,  Service &service);
QDataStream &operator>>(QDataStream &in, Service &service);
Q_DECLARE_METATYPE(Service*);

#endif // SERVICE_H

Code:

#include "service.h"
#include <QStringList>
#include <QDebug>


Service::Service()
{
    this->name="";
    this->address="";
    this->user="";
    this->password="";
    this->nick="";
    this->active=true;
}

Service::Service(QString name, QString address, bool needU, QString user,
        bool needP, QString password, bool needN, QString nick,bool active){
    this->name=name;
    this->address=address;
    this->user=user;
    this->password=password;
    this->nick=nick;
    this->needN=needN;
    this->needP=needP;
    this->needU=needU;
    this->active=active;

}

QString Service::getAddress(){
    return address;
}
QString Service::getName(){
    return name;
}

QString Service::getUser(){
    return user;
}
QString Service::getPassword(){
    return password;
}

QString Service::getNick(){
    return nick;
}

.......

bool Service::isActive(){
    return this->active;
}

bool Service::needUser(){
    return this->needU;
}
bool Service::needPass(){
    return this->needP;
}
bool Service::needNick(){
    return this->needN;
}

QDataStream &operator<<(QDataStream &out,  Service &service)
{
    out << service.getName() << service.getAddress() << service.needUser() << service.getUser()
            << service.needPass() << service.getPassword() << service.needNick() << service.getNick()
            << service.isActive();

    return out;
}

QDataStream &operator>>(QDataStream &in, Service &service)
{
    QString name;
    QString address;
    QString user;
    QString password;
    QString nick;
    bool needU, needP, needN, active;

    in >> name >> address >> needU >> user >> needP >> password >> needN >> nick >> active;
    service = Service(name, address, needU, user, needP, password, needN, nick, active);
    return in;
}

and here how i'm using it:
load:
Code:

QVariant var = settings->value("services");
        QByteArray array;
        array =var.value<QByteArray>();
        QDataStream data(&array,QIODevice::ReadWrite);
      data >> services;

save:
Code:

QByteArray array;
      QDataStream data(&array, QIODevice::ReadWrite);
      data << services;
      QVariant var;
      var.setValue(array);
      //}
    settings->setValue("services", var);

where:
QList<Service*> *services;

i hope u can help me :o

gri 2010-06-03 21:49

Re: QDataStream ad QList problem!
 
First, please make the writing function const.
Code:

QDataStream &operator<<(QDataStream &out,  const Service &service);
QDataStream &operator>>(QDataStream &in, Service &service);

The second is, you can only use non-pointer types of Service when exporting the whole QList to a QDataStream. The following would work:
Code:

QList<Service> services;
mystream << services;

If you can't change to non-pointer type, you will have to iterate through the list at your own.
Code:

QList<Service*> services;
mystream << services.size();
foreach(Service* service, services)
  mystream << *service;

Edit: Also please stay away from creating QList<>s on the heap :)

Quote:

the strange thing is that << seems to work with QList<Service*>!
If that's the only problem, try this:
Code:

mystream << *services;

saxen 2010-06-03 22:00

Re: QDataStream ad QList problem!
 
Quote:

Originally Posted by gri (Post 698474)
First, please make the writing function const.
Code:

QDataStream &operator<<(QDataStream &out,  const Service &service);
QDataStream &operator>>(QDataStream &in, Service &service);


mmm why do that?! btw if i make it const i've this:
Code:

error: passing ‘const Service’ as ‘this’ argument of ‘QString Service::getName()’ discards qualifiers
To solve i've to add const in getName()(and other get metods), like:
getName() const { return name;}



Quote:

Originally Posted by gri (Post 698474)
The second is, you can only use non-pointer types of Service when exporting the whole QList to a QDataStream. The following would work:
Code:

QList<Service> services;
mystream << services;


that's would be good, but i've to pass these pointers to other class in order to edit them, so i think i can't use non-pointer...am i right?! :o



Quote:

Originally Posted by gri (Post 698474)
If you can't change to non-pointer type, you will have to iterate through the list at your own.
Code:

QList<Service*> services;
mystream << services.size();
foreach(Service* service, services)
  mystream << *service;


nice this way, but...should i store manually the list's size before store elements? :o



Quote:

Originally Posted by gri (Post 698474)
Edit: Also please stay away from creating QList<>s on the heap :)

what's the matter with this?! i'm still so confused about reference and pointer :confused:

Joorin 2010-06-03 22:06

Re: QDataStream ad QList problem!
 
Quote:

what's the matter with this?! i'm still so confused about reference and pointer
Pointers refer to any memory, be it on the stack or the heap. Where you allocate it has nothing to do with the pointer per se.

But, when the memory is deallocated (using delete or leaving the current scope) the pointer points at memory that you can not access without triggering an error.

References share some of the pointer semantics but have some extra constraints and properties. For one, a reference always has to have a value that can be referenced. (Hence the name.)

Venemo 2010-06-03 22:06

Re: QDataStream ad QList problem!
 
Hey,

I also encountered the exact same situation.
Gri and the others wrote down everything well, but let me add a few side notes.

You can basically serialize a QList<T> if T is serializable. (Meaning: it has a << operator.)

I wrote for myself a class called QSettingsManager for this purpose. You can view the code here and the entire app in this repository.

Feel free to use it in your app, too.
There are also examples for serialization, too.

The relevant part is this:

Code:

template<typename T>
void QSettingsManager::storeBinary(const QString& key, const T& value)
{
    checkSettingsObj();
    QByteArray array;
    QDataStream stream(&array, QIODevice::WriteOnly);
    stream << value;
    storeSetting(key, array);
}

You can call it like this, for example:

Code:

QList<QString> myList;
... // fill myList with values
QSettingsManager::storeBinary<QList<QString> >("settingskey", myList);


gri 2010-06-03 22:10

Re: QDataStream ad QList problem!
 
Code:

error: passing ‘const Service’ as ‘this’ argument of ‘QString Service::getName()’ discards qualifiers
Getters should always be const! So the error message is right.

Quote:

that's would be good, but i've to pass these pointers to other class in order to edit them, so i think i can't use non-pointer...am i right?! :o
You should read something about pointer dereferencing. Also non-pointer variables can be made to pointer variables and vice versa.
Code:

Service service;
Service* servicePointer = &service;
Service& serviceReference = service;
Service& serviceReferenceFromPointer = *service;

Quote:

nice this way, but...should i store manually the list's size before store elements? :o
Otherwise you won't know how much elements you have to read the next time :) If you create a QList<Service*> and call the shift operator for the QDataStream, your datastream will fill something strange (or it crashes). Since the QList operator for the QDataStream does not know that it should create a Service instance with "new".

Quote:

what's the matter with this?! i'm still so confused about reference and pointer :confused:
References and pointers are the same in some ways. I can't explain this in english, maybe you should read some c++ tutorials for that.

saxen 2010-06-03 22:24

Re: QDataStream ad QList problem!
 
thanks for explanation joorin :o

Quote:

Originally Posted by Venemo (Post 698506)

You can basically serialize a QList<T> if T is serializable. (Meaning: it has a << operator.)

that's why i said that << and >> work well with "Service*". so T is serializable! :o

Quote:

Originally Posted by Venemo (Post 698506)
I wrote for myself a class called QSettingsManager for this purpose. You can view the code here and the entire app in this repository.

is this?! :confused:
http://vcs.maemo.org/svn/eve-watcher...ngsmanager.cpp


now i'm going to try this:
1) put away QList<> from the heap
2) try to use QList<Service> instead of QList<Service*>
3) if 2 won't work, i'll try to save element by element.


@gri, if i can use non-pointer to do that...i wonder...when a pointer is necessary!? :confused:

Venemo 2010-06-03 22:32

Re: QDataStream ad QList problem!
 
Quote:

Originally Posted by saxen (Post 698548)

Yeah, plus the header file.
(The template methods which I quoted earlier are in the header file.)
You can check out the entire app so you can see how it works, if you wish.

Quote:

Originally Posted by saxen (Post 698548)
that's why i said that << and >> work well with "Service*". so T is serializable!

A pointer is an address in the memory.
It is (basically) a 32-bit integer of 32-bit machines and a 64-bit integer on 64-bit machines.
Because of this, every pointer is "serializable". Still, you don't gain anything by storing a random memory address.

Why?
1. There is no guarantee that the same address will be yours next time.
2. The data stored in that address is erased when your app is closed, so no point in storing its address anyway.

Solution:
Store the data itself, not its address.

Quote:

Originally Posted by saxen (Post 698548)
@gri, if i can use non-pointer to do that...i wonder...when a pointer is necessary!? :confused:

Pointers are necessary for a range of nasty things.
This simple task is not one of them.

Joorin 2010-06-03 22:46

Re: QDataStream ad QList problem!
 
This isn't directly related to you question, but it might explain something.

Code:

int i = 17;
int *pointer_to_int = &i;

The above snippet describes storage of an integer, 17, and a pointer to the address in memory where this integer is stored.

Using this pointer, you can change the stored value:
Code:

*pointer_to_int = 4711;
The pointer lets you pass around data in the form of a reference that, when dereferenced, gives you the actual data.

Continuing from above, you can extend this indirection:
Code:

int **pointer_to_pointer_to_int = &pointer_to_int;
This describes a pointer pointing to a pointer pointing at an integer, 17, which lets you manipulate both the integer and the pointer that points to it. Further indirection is possible but this is often the level that is interesting because being able to change what a pointer points to instead of the value that the pointer point to let's you, for example, iterate over lists or return pointers from functions.

Code:

int do_stuff(char *foo, char **error) {
  ...
}

By calling do_stuff with a pointer to a pointer, it is possible to return a pointer to something that has been allocated inside do_stuff.

References can in most cases be seen as lacking the second level of indirection. The compiler imposes limitations on what you can do with a reference and dictates when they have to be initialized. It is not interesting to change references like pointers because the reference already gives you direct access to whatever it references

If you play around with it a bit, you'll understand more. Take the time to look at one of the many introductions to C++ online.

saxen 2010-06-03 22:49

Re: QDataStream ad QList problem!
 
ok with 2) i've solve problem with >> operator...but anything else is working xD

i'm sure is a reference/pointer stuff. i mean, i'm adding to my QList<Service> a reference Service service in a method called "addItems". Will it be this reference deleted once the addItems is over even if it's now linked in my list?!

so should i use Service * service = new Service() and then add with list->append(*service) ?!
:confused::confused::confused:

Joorin 2010-06-03 22:53

Re: QDataStream ad QList problem!
 
Quote:

Originally Posted by saxen (Post 698596)
ok with 2) i've solve problem with >> operator...but anything else is working xD

i'm sure is a reference/pointer stuff. i mean, i'm adding to my QList<Service> a reference Service service in a method called "addItems". Will it be this reference deleted once the addItems is over even if it's now linked in my list?!

so should i use Service * service = new Service() and then add with list->append(*service) ?!
:confused::confused::confused:

Either you have a list of pointers or a list of what those pointer would have pointed at:

Code:

| pointer | pointer | pointer |

or

| Service | Service | Service |

As Venemo says, saving pointers to memory that you no longer have allocated makes no sense (the first case) but to actually save the Service objects, with everything that's in them (the second case) makes more sense.

Venemo 2010-06-03 23:02

Re: QDataStream ad QList problem!
 
Quote:

Originally Posted by saxen (Post 698596)
ok with 2) i've solve problem with >> operator...but anything else is working xD

i'm sure is a reference/pointer stuff. i mean, i'm adding to my QList<Service> a reference Service service in a method called "addItems". Will it be this reference deleted once the addItems is over even if it's now linked in my list?!

so should i use Service * service = new Service() and then add with list->append(*service) ?!
:confused::confused::confused:

No. Don't get confused with this.
When you append an item to a collection in such a way, or assign it to a variable, it gets copied. (Its copy constructor or operator= gets called.)

Eg.
Code:

MyClass item; //creating a new item
item.stuff = 42;
MyClass item2 = item; //behind the scenes, item2 copies item
item.stuff = 8; //this line doesn't change item2

Note that by default, the MyClass type can't be copied.
You need to tell HOW it is gonna be copied.
That's why there is a copy constructor or an operator=.

Basically,
Code:

item2 = item;
is the same as
Code:

item2.operator=(item);
and only works if there is a
Code:

MyClass::operator=(const MyClass& other) { ... }
method in your class.

And
Code:

MyClass item2 = item;
is the same as
Code:

MyClass item2(item);
and only works if there is a
Code:

MyClass::MyClass(const MyClass& other) { ... }
constructor in your code.

saxen 2010-06-03 23:08

Re: QDataStream ad QList problem!
 
Quote:

Originally Posted by Venemo (Post 698618)
No. Don't get confused with this.
When you append an item to a collection in such a way, or assign it to a variable, it gets copied. (Its copy constructor or operator= gets called.)

Eg.
Code:

MyClass item; //creating a new item
item.stuff = 42;
MyClass item2 = item; //behind the scenes, item2 copies item
item.stuff = 8; //this line doesn't change item2


even when i get from collection?! :confused:

ok that's the point, i've a list of Service in my main classes. i've to share this list with other classes, like "EditService". how can i pass list, or elements, to other class in order to make them change original list?! :(

with the old list of pointer it worked well(they actually changed value of original list), but as u said save pointer doesn't make sense. so what i'm supposed to do?!

back with pointer list changing saving function?! or there are other solutions!? :o

Venemo 2010-06-03 23:13

Re: QDataStream ad QList problem!
 
Quote:

even when i get from collection?!
Yes, exactly.
BTW, Qt's collections give back const references to items stored within them.

Quote:

Originally Posted by saxen (Post 698632)
ok that's the point, i've a list of Service in my main classes. i've to share this list with other classes, like "EditService". how can i pass list, or elements, to other class in order to make them change original list?! :(

You can pass around a QList<Service>* to achieve that.
Note that QList<Sevice*> is NOT QList<Service>* !!

(BTW, I edited my previous post to make it more clear how C++ works.)

saxen 2010-06-03 23:21

Re: QDataStream ad QList problem!
 
Quote:

Originally Posted by Venemo (Post 698641)
Yes, exactly.
BTW, Qt's collections give back const references to items stored within them.

You can pass around a QList<Service>* to achieve that.
Note that QList<Sevice*> is NOT QList<Service>* !!

(BTW, I edited my previous post to make it more clear how C++ works.)

yes thanks now is more clear ;)

gri said to not use list in heap, so no QList<Service>* or not!? :o


if i use it like this(not real code):

main class:
QList<Service> * services;
EditService edit(services);

EditService class:
Service service = services.at(0);
service.changeSomething();


service in QList has not be really changed...am i right!? so the only solution is user a list of pointer :confused:

Venemo 2010-06-03 23:50

Re: QDataStream ad QList problem!
 
Quote:

Originally Posted by saxen (Post 698654)
service in QList has not be really changed...am i right!? so the only solution is user a list of pointer :confused:

Nooo...

Okay. You have a pointer to a list that contains items.

If you give a pointer to someone, it can do whatever it wants to the memory where the pointer points to.

So, basically:
yes, you can change the collection this way.

Again:
Feel free to check how I do this in my own app.
(Hint: CharacterListWindow, EveRefresher, and EveConnector all share a QList<EveCharacter>* and do stuff with it all the time.)

saxen 2010-06-04 11:27

Re: QDataStream ad QList problem!
 
ok i'll give a look to your app! thanks again, i'll let you know ;)

saxen 2010-06-04 12:23

Re: QDataStream ad QList problem!
 
i dunno how, but now it works :P
jk, i know how...i've change a bit the original code :)

Now i've a QList<Service*> services, so no list in the heap(as gri suggested). I still have a list of pointer but change code in order to save object pointed instead of pointer(as it logically should be).

In service class now i've:
Q_DECLARE_METATYPE(Service);
Q_DECLARE_METATYPE(Service*);

the first is necessary to save object:
Code:

QByteArray array;
      QDataStream data(&array, QIODevice::ReadWrite);
      data << services.size();
      foreach(Service* service, services){
        data << *service;
    }

and load:
Code:

QVariant var = settings->value("services");
        QByteArray array;
        array =var.value<QByteArray>();
        QDataStream data(&array,QIODevice::ReadWrite);
        int size;
        data>> size;
      for(int i=0; i<size;i++){
            Service *service = new Service();
            data >> *service;
            services.append(service);
        }

the second one is to set data in QListWidget:
Code:

QListIterator<Service*> i(services);
    while(i.hasNext()){
        Service *service = new Service();
        service = i.next();
        QListWidgetItem * item= new QListWidgetItem(service->getName());
        item->setSizeHint(QSize(300, 100));
        item->setTextAlignment(Qt::AlignCenter);
      QVariant var;
        var.setValue(service);
        item->setData(Qt::UserRole, var);
        ui->listWidget->addItem(item);
    }

and share pointer to other classes:
Code:

Service *service= new Service();
    service = (item->data(Qt::UserRole).value<Service*>());
    ConfigWindow *configwindow = new ConfigWindow(service, this);
    configwindow->show();

using a list of pointer i can't use << and >> operator with list, so i've to manage single elements!
maybe it's not pretty elegant, but works well :)

thanks to all for help :)

ps. venemo your code will be usefull when i'll get into "user interface", i've seen interesting code about rotation management ;)

gri 2010-06-04 14:45

Re: QDataStream ad QList problem!
 
Quote:

Originally Posted by saxen (Post 699456)
i've seen interesting code about rotation management ;)

I don't know what you've seen but you could also take a look at the orientation helper class and example I wrote. Maybe it helps you :)

https://garage.maemo.org/plugins/scm...ms&view=markup (usage)
https://garage.maemo.org/plugins/scm...ms&view=markup (orientation helper class)

Screenshots:
http://gri.not-censored.com/orientat...horizontal.png
http://gri.not-censored.com/orientat...t/vertical.png

saxen 2010-06-04 15:32

Re: QDataStream ad QList problem!
 
really nice code gri, i think i'm gonna try it :P
btw i've a question about ui...how to set window size?! i mean max res is 800*480 or 480*800 but what's about status bar?! :S

gri 2010-06-04 15:48

Re: QDataStream ad QList problem!
 
Quote:

Originally Posted by saxen (Post 699710)
really nice code gri, i think i'm gonna try it :P
btw i've a question about ui...how to set window size?! i mean max res is 800*480 or 480*800 but what's about status bar?! :S

Why do you want to set the windows sizes? Dialogs have the size they need. Windows take the most space they can get. The layouting is done by Qt. Think of porting to another device: It may have completely different screen sizes. Let Qt do the work and don't care about them :)

saxen 2010-06-04 15:57

Re: QDataStream ad QList problem!
 
mmm so what's about dialogs(or widget) size?! should i've to fix it?! :o

gri 2010-06-04 16:04

Re: QDataStream ad QList problem!
 
Quote:

Originally Posted by saxen (Post 699735)
mmm so what's about dialogs(or widget) size?! should i've to fix it?! :o

You know how to use the layouts?
Just open the Qt Designer and play around with layouting (there are tool buttons for that). You will also need to understand the sizePolicy options.

That's all you need. No pixel coordinates or something else :)

saxen 2010-06-04 16:07

Re: QDataStream ad QList problem!
 
i guess layout will do everything about screensize!
btw once app's core is done i'll start move around in order to create a "cute" ui :)

thanks again!

saxen 2010-06-04 18:15

Re: QDataStream ad QList problem!
 
could you suggest me some guide about ui creation!? i've found a lot of documents but i'd like to found a good one to learn how to create ui ;)

gri 2010-06-04 18:34

Re: QDataStream ad QList problem!
 
Quote:

Originally Posted by saxen (Post 699903)
could you suggest me some guide about ui creation!? i've found a lot of documents but i'd like to found a good one to learn how to create ui ;)

The best source is the Qt documentation itself. Take a look in your Qt Assistant.

http://doc.qt.nokia.com/qt-maemo-4.6...d-layouts.html
http://doc.qt.nokia.com/qt-maemo-4.6...s-layouts.html

saxen 2010-06-05 10:36

Re: QDataStream ad QList problem!
 
thanks for these links! btw i still don't understand how set items size properly in order to fix them in main widget :O

where can i find a real example!? i mean a *.ui file from some app :O

EDIT. ok i've found a good one :p


All times are GMT. The time now is 00:59.

vBulletin® Version 3.8.8