semlanik / qtprotobuf

Protobuf generator and bindings for Qt framework
https://semlanik.github.io/qtprotobuf
MIT License
169 stars 38 forks source link

QSharedPointer и списки свойств #229

Closed lubagov closed 3 years ago

lubagov commented 3 years ago

Question Мне интересна одна вещь. QSharedPointer сравнивает адреса указателей в операторе "==" а не сами объекты. Все элементы в списках, на подобии:

message Content{
  repeated ContentItem products = 1;
}
message ContentItem {
  int32 product_id = 1;
  string product_name = 2;
  string url = 4;
  string name = 5;
}

Преобразуются в структуру:

class ContentItem;
using ContentItemRepeated = QList<QSharedPointer<ContentItem>>;

Теперь когда мы пытаемся сравнить 2 объекта:

Content content1; 
Content content1;
if(content1==content2){
...
}

То, как правило получим true если все указатели, всех элементов списков равны, но не сами элементы. Вроде как подход верный в плане QML дизайна. Но в C++ когде я хочу сравнить 2 объекта полученные из разных RPC вызовов, перед дальнейшей обработкой, если они различаются, то это не то, что я ожидаю.

semlanik commented 3 years ago

Приветствую @lubagov, если я правильно понял вопрос, то думаю ответ кроется в простом примере:

int a = 10;
int *aptr1 = &a;
int *aptr2 = &a;

if(aptr1 == aptr2) {
     assert(*aptr1 == *aptr2);
}

Другими словами, я не представляю ситуации когда по одному и тому же адресу в памяти лежит разное значение. Обратное естественно неверно.

Единственное различие может быть если 2 указателя трактуются по разному в момент сравнения, например:

int a = 65535;
int *aptr1 = &a;
char *aptr2 = reinterpret_cast<char*>(&a);

if(aptr1 == reinterpret_cast<int*>(aptr2)) {
     assert(*aptr1 == *aptr2);
}

Но насколько я помню такого в коде быть не должно, и строгая статическая типизация блокирует такое поведение.

Пока писал ответ на вопрос, мне пришел в голову другой вопрос. А что если элементы списков лежат в разном порядке в QList? С точки зрения с++ эти списки не равны, но с точки зрения protobuf они равны. Этот момент мне надо уточнить с референсными имплементациями protobuf, и возможно сделать по аналогии.

З.Ы.: English, please :)

Перечитал вопрос и понял что понял его неверно. Вы правы если объекты получены из двух разных вызовов то листы будут разными. Это проблема.

lubagov commented 3 years ago

Ну да, как бы нужен, перегруженный оператор ==, но это противоречит логике QSharedPointer... который сравнивает указатели. Но сравнение указателей не то что хочется..

bool operator==(const QSharedPointer<ContentItem> left, const QSharedPointer<ContentItem> right){
    return *left==*right;
}

Упс: А что если элементы списков лежат в разном порядке в QList? С точки зрения с++ эти списки не равны, но с точки зрения protobuf они равны.

А что они могут персортироваться внутри Repeat? В некоторых вызовах, мне важен порядок. И списки в разном порядке, это разные списки (плейлист). В некоторых не важен, как контент(список файлов для загрузки). И кажется, с контентом, мне луче использовать map, с ключом "product_id"... так точно и порядок будет верный, и у меня проще код получится (из плейлиста ищу по id элемент в контенте) :-)

semlanik commented 3 years ago

Упс: А что если элементы списков лежат в разном порядке в QList? С точки зрения с++ эти списки не равны, но с точки зрения protobuf они равны.

А что они могут персортироваться внутри Repeat? В некоторых вызовах, мне важен порядок. И списки в разном порядке, это разные списки (плейлист). В некоторых не важен, как контент(список файлов для загрузки). И кажется, с контентом, мне луче использовать map, с ключом "product_id"... так точно и порядок будет верный, и у меня проще код получится (из плейлиста ищу по id элемент в контенте) :-)

Да к сожалению порядок отправки элементов вроде как не гарантирован. Надо перечитать, возможно меня подводит память и это касается только map.

И да память меня подводит: repeated: this field can be repeated any number of times (including zero) in a well-formed message. The order of the repeated values will be preserved.