Russian Qt Forum
Май 06, 2024, 01:59 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2 3   Вниз
  Печать  
Автор Тема: тип size_t и сравнение указателей  (Прочитано 16762 раз)
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« : Март 19, 2011, 15:50 »

Приветствую)

У меня такой вопрос:
Имеется два указателя на объекты двух разных типов (A и B).
Хотелось бы сравнивать не сами указатели, а их значения приведённые к типу size_t.
Вот пример:
Код
C++ (Qt)
class A {
...
};
 
class B {
...
};
 
A *a = new A;
B *b = new B;
 
size_t address_a = reinterpret_cast<size_t>(a);
size_t address_b = reinterpret_cast<size_t>(b);
 
if (address_a != address_b)
   ....
else
   ....
 
 
Т.е. корректно ли это будет всегда и везде работать? И есть ли какие-нить грабли?
 Непонимающий
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #1 : Март 19, 2011, 16:05 »

Т.е. корректно ли это будет всегда и везде работать? И есть ли какие-нить грабли?
 Непонимающий
Не хочется делать обязывающих заявлений, но да, всегда. Практичнее/приятнее привести к (char *) вместо size_t
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #2 : Март 19, 2011, 16:08 »

Т.е. корректно ли это будет всегда и везде работать? И есть ли какие-нить грабли?
 Непонимающий
Не хочется делать обязывающих заявлений, но да, всегда. Практичнее/приятнее привести к (char *) вместо size_t
Спасибо)) Прям камень с души)
А в чём приимущество приведения к (char*) по сравнению size_t?
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #3 : Март 19, 2011, 16:15 »

А в чём приимущество приведения к (char*) по сравнению size_t?
Чисто субъективное, приведение к  (char *) весьма популярно в чистом "С", т.е. "Вас сразу поймут"  Улыбающийся
Записан
SimpleSunny
Гость
« Ответ #4 : Март 19, 2011, 16:26 »

Не должно везде и всюду корректно работать.
Так как никто не гарантирует, что указатель поместится в size_t.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #5 : Март 19, 2011, 16:34 »

Не должно везде и всюду корректно работать.
Так как никто не гарантирует, что указатель поместится в size_t.
Мне кажется это следует из правил адресной арифметики "С" (sizeof возвращает размер типа size_t)
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #6 : Март 19, 2011, 16:40 »

Я тут нашёл статейку о size_t и ptrdiff_t
http://www.realcoding.net/articles/chto-takoe-sizet-i-ptrdifft.html

В которой говориться, что в принципе проблем быть не должно, поскольку его (size_t) для этого и придумали, но есть исключение: это указатели на методы классов.
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
blood_shadow
Гость
« Ответ #7 : Март 19, 2011, 18:49 »

мне кажется будет еще не плохо привести указатели к типу void* и сравнить их на равенство,
к тому же к void* можно неявно привести и операция сравнение это практически единственная что можно делать с void*
Записан
brankovic
Гость
« Ответ #8 : Март 19, 2011, 19:07 »

Я тут нашёл статейку о size_t и ptrdiff_t
http://www.realcoding.net/articles/chto-takoe-sizet-i-ptrdifft.html

В которой говориться, что в принципе проблем быть не должно, поскольку его (size_t) для этого и придумали, но есть исключение: это указатели на методы классов.

У меня были проблемы с реинтерпрет кастами, но я приводил указатель на A к указателю на B и пытался в нём что-то менять. Компилятору это не понравилось, он сгенерил неверный код. Поэтому в gcc такие преобразования делаю через юнион. В случае с size_t должно работать, но более правильно как blood_shadow сказал про void*:

Код
C++ (Qt)
inline bool equal (void *a, void *b) { return a == b; }
 
A *a; B *b;
if (equal (a, b))
 

или

Код
C++ (Qt)
A *a; B *b;
if (std::equal <void *> (a, b))
 

Без реинтерпертов лучше обойтись, чтобы читающих код не пугать.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #9 : Март 19, 2011, 19:15 »

Без реинтерпертов лучше обойтись, чтобы читающих код не пугать.
Верное замечание, незачем выставлять мнимую "крутизну", лучше
Код
C++ (Qt)
if ((char *) A == (char *) B))
 
Скромно и хорошо
Записан
brankovic
Гость
« Ответ #10 : Март 19, 2011, 19:21 »

Код
C++ (Qt)
if ((char *) A == (char *) B))
 
Скромно и хорошо

сишный каст -- зло!! ..но для краткости сойдёт Улыбающийся
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #11 : Март 19, 2011, 19:38 »

сишный каст -- зло!! ..но для краткости сойдёт Улыбающийся
Ой, мама дорогая, та где ж там такое зло?  Улыбающийся Хотели сравнить 2 адреса - ну и сделали. Или адрес уже "не (совсем) адрес" а нечто задроченое с помощью вумных xxx_cast ?  Улыбающийся
Записан
brankovic
Гость
« Ответ #12 : Март 19, 2011, 19:42 »

сишный каст -- зло!! ..но для краткости сойдёт Улыбающийся
Ой, мама дорогая, та где ж там такое зло?  Улыбающийся Хотели сравнить 2 адреса - ну и сделали. Или адрес уже "не (совсем) адрес" а нечто задроченое с помощью вумных xxx_cast ?  Улыбающийся

Вот скажет вам компилятор в один прекрасный день: "at line 123, error: сишный каст -- зло!!" и будет прав, а вам и сказать будет нечего.
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #13 : Март 19, 2011, 19:55 »

Собственно, вопрос возник в контексте оптимизации libssc.
Там ранее при создании нового соединения или, например, при записи приоритета соединения и т.п. каждый раз проверяется весь список соединений и каждый раз при этом вызывается dynamic_cast (который по природе своей не быстр). Вот чтобы избавится от лишних его вызовов, я ввёл в базовый класс (base_connection) виртуальный метод:
Код
C++ (Qt)
typedef size_t address_type // или typedef void* address_type или typedef char* address_type
...
virtual address_type address() const = 0;
 

И соответственно в унаследуемых классов этот метод определяю:
Код
C++ (Qt)
address_type address() const { return reinterpret_cast<address_type>(m_receiver); }
 
Это всё позволяет не вызывать лишний раз dynamic_cast в функции compre:
Код
C++ (Qt)
bool compare(base_connection2<S_arg1, S_arg2> *bc) const {
if ((bc->type() == MEM_FUN_CONNECTION) && (bc->address() == address())) {
   mem_fun_connection2<S_arg1, S_arg2, R_receiver, R_return, R_arg1, R_arg2> *mfc = dynamic_cast<mem_fun_connection2<S_arg1, S_arg2, R_receiver, R_return, R_arg1, R_arg2> *>(bc);
if (m_slot_is_const)
   return (mfc) ? (mfc->m_slot_pack.m_const_slot == m_slot_pack.m_const_slot) : false;
return (mfc) ? (mfc->m_slot_pack.m_slot == m_slot_pack.m_slot) : false;
}
return false;
   }
 
Собственно вот..
Спасибо)
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
brankovic
Гость
« Ответ #14 : Март 19, 2011, 20:15 »

Вот чтобы избавится от лишних его вызовов, я ввёл в базовый класс (base_connection) виртуальный метод:
Код
C++ (Qt)
typedef size_t address_type // или typedef void* address_type или typedef char* address_type
...
virtual address_type address() const = 0;
 

можно уменьшить и убыстрить так:
1. заменить size_t на void *
2. убрать у функции address атрибут virtual и =0
3. в теле address в базовом классе вернуть this (reinterpret_cast не нужен для преобразования в void*)
4. убрать address из наследников

надо иметь ввиду, что вызов dynamic_cast по скорости близок к вызову виртуальной функции, поэтому заменяя dynamic_cast на виртуальную функцию много не выиграешь.

но я бы сделал ещё радикальнее, перед вызовом compare (a, b) вставил бы:

Код
C++ (Qt)
if (static_cast <void*> (&a) == &b)
 

 -- так не будет расходоваться время на вызов виртуальной же функции compare, если адреса a и b сразу не равны.
Записан
Страниц: [1] 2 3   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.217 секунд. Запросов: 22.