Можно ли определить, является ли тип наследником данного, на шаблонах?
От: Аноним  
Дата: 12.02.13 13:20
Оценка:
Есть полиморфный массив, то есть массив указателей BaseItem*, каждый из которых реально указывает на объект какого-то класса-наследника BaseItem. Наследников много и все они образуют довольно ветвистое дерево.

Нужна шаблонаня функция вида GetItem<T>(int i), которая должна сделать следующее: если реальный тип i-того элемент массива реально является классом T или наследником T (где в качестве T передается некоторый наследник BaseItem), то вернуть адрес этого объекта, иначе вернуть null.
Возможно ли такое? (без буста).
Re: Можно ли определить, является ли тип наследником данного, на шаблонах?
От: watch-maker  
Дата: 12.02.13 13:25
Оценка: +2
Здравствуйте, Аноним, Вы писали:

А>Нужна шаблонаня функция вида GetItem<T>(int i), которая должна сделать следующее: если реальный тип i-того элемент массива реально является классом T или наследником T (где в качестве T передается некоторый наследник BaseItem), то вернуть адрес этого объекта, иначе вернуть null.

А>Возможно ли такое? (без буста).
return dynamic_cast<T*>(array[i]);
Re: Можно ли определить, является ли тип наследником данного, на шаблонах?
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 12.02.13 13:57
Оценка: -2
Здравствуйте, Аноним, Вы писали:

А>Есть полиморфный массив, то есть массив указателей BaseItem*, каждый из которых реально указывает на объект какого-то класса-наследника BaseItem. Наследников много и все они образуют довольно ветвистое дерево.


А>Нужна шаблонаня функция вида GetItem<T>(int i), которая должна сделать следующее: если реальный тип i-того элемент массива реально является классом T или наследником T (где в качестве T передается некоторый наследник BaseItem), то вернуть адрес этого объекта, иначе вернуть null.

Толком из этого ничего хорошего не выйдет. Ты пытаешься мешать динамику и статику, а это не сработает тут. Единственный веный путь использовать rtti и dynamic_cast.
Sic luceat lux!
Re: Можно ли определить, является ли тип наследником данного, на шаблонах?
От: Vamp Россия  
Дата: 12.02.13 14:11
Оценка: +2
А>Нужна шаблонаня функция вида GetItem<T>(int i), которая должна сделать следующее: если реальный тип i-того элемент массива реально является классом T или наследником T (где в качестве T передается некоторый наследник BaseItem), то вернуть адрес этого объекта, иначе вернуть null.
В 99% случаев подобный вопрос указывает на ошибку проектирования.
Да здравствует мыло душистое и веревка пушистая.
Re[2]: Можно ли определить, является ли тип наследником данного, на шаблонах?
От: Serg27  
Дата: 12.02.13 14:12
Оценка: -2
Здравствуйте, watch-maker, Вы писали:
А>>Возможно ли такое? (без буста).
WM>
return dynamic_cast<T*>(array[i]);

dynamic_cast выкидывает исключение если ему подсунуть нулевой указатель. Если это не желательно, а хотелось бы получить либо указатель, либо нулевой указатель, то можно чуть модифицировать:
return (array[i] != NULL) ? dynamic_cast<T*>(array[i]) : NULL;


Ну и надо помнить, что это использование RTTI и это дает некоторое уменьшение производительности
Re[3]: Можно ли определить, является ли тип наследником данного, на шаблонах?
От: uzhas Ниоткуда  
Дата: 12.02.13 14:15
Оценка: +1
Здравствуйте, Serg27, Вы писали:

S>dynamic_cast выкидывает исключение если ему подсунуть нулевой указатель

это неверно. возвращается ноль

S>Ну и надо помнить, что это использование RTTI и это дает некоторое уменьшение производительности

это верно
Re[3]: Можно ли определить, является ли тип наследником данного, на шаблонах?
От: watch-maker  
Дата: 12.02.13 14:19
Оценка:
Здравствуйте, Serg27, Вы писали:

WM>>
return dynamic_cast<T*>(array[i]);

S>dynamic_cast выкидывает исключение если ему подсунуть нулевой указатель.
Нет.

5.2.7 Dynamic cast
4. If the value of v is a null pointer value in the pointer case, the result is the null pointer value of type T.

Re[4]: Можно ли определить, является ли тип наследником данного, на шаблонах?
От: Serg27  
Дата: 12.02.13 15:00
Оценка:
Здравствуйте, uzhas, Вы писали:

U>Здравствуйте, Serg27, Вы писали:


S>>dynamic_cast выкидывает исключение если ему подсунуть нулевой указатель

U>это неверно. возвращается ноль

Для VS2003 и 2010 это так. Цитата из MSDN: здесь
The value of a failed cast to pointer type is the null pointer. A failed cast to reference type throws a bad_cast Exception. If expression does not point to or reference a valid object, a __non_rtti_object exception is thrown.
Re[5]: Можно ли определить, является ли тип наследником данного, на шаблонах?
От: watch-maker  
Дата: 12.02.13 15:15
Оценка:
Здравствуйте, Serg27, Вы писали:

S>Здравствуйте, uzhas, Вы писали:


U>>Здравствуйте, Serg27, Вы писали:


S>>>dynamic_cast выкидывает исключение если ему подсунуть нулевой указатель

U>>это неверно. возвращается ноль

S>Для VS2003 и 2010 это так. Цитата из MSDN: здесь

S>The value of a failed cast to pointer type is the null pointer. A failed cast to reference type throws a bad_cast Exception. If expression does not point to or reference a valid object, a __non_rtti_object exception is thrown.

Ты не то цитируешь. Смотри по своей же ссылке:

A null pointer value is converted to the null pointer value of the destination type by dynamic_cast.

Re[6]: Можно ли определить, является ли тип наследником данного, на шаблонах?
От: Serg27  
Дата: 12.02.13 15:24
Оценка:
Здравствуйте, watch-maker, Вы писали:

WM>Ты не то цитируешь. Смотри по своей же ссылке:

A null pointer value is converted to the null pointer value of the destination type by dynamic_cast.


Да, действительно. Но это мое мнение основано на реальном баге в производственном коде. Возможно за давностью лет что-то уже забылось, но сейчас не на работе — проверить не могу. Завтра посмотрю более точную причину. Да и было это с VS2003. Ну все равно завтра...
Re[7]: Можно ли определить, является ли тип наследником данного, на шаблонах?
От: uzhas Ниоткуда  
Дата: 12.02.13 16:13
Оценка:
Здравствуйте, Serg27, Вы писали:

S>Но это мое мнение основано на реальном баге в производственном коде.


я могу потелепатировать: в студии dynamic_cast указателей кидает исключение в случае, если указатель пришел из библиотеки, которая скомпилирована без поддержки rtti
исключение вроде имеет тип __non_rtti_object
про баги не слышал, а с таким поведением встречался
Re: Можно ли определить, является ли тип наследником данного, на шаблонах?
От: jazzer Россия Skype: enerjazzer
Дата: 13.02.13 00:22
Оценка: -1
Здравствуйте, Аноним, Вы писали:

А>Есть полиморфный массив, то есть массив указателей BaseItem*, каждый из которых реально указывает на объект какого-то класса-наследника BaseItem. Наследников много и все они образуют довольно ветвистое дерево.


А>Нужна шаблонаня функция вида GetItem<T>(int i), которая должна сделать следующее: если реальный тип i-того элемент массива реально является классом T или наследником T (где в качестве T передается некоторый наследник BaseItem), то вернуть адрес этого объекта, иначе вернуть null.

А>Возможно ли такое? (без буста).

Корректно это делается через паттерн Visitor. Шаблоны тут не помогут, так как у тебя динамика, а не статика.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[2]: Можно ли определить, является ли тип наследником данного, на шаблонах?
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 13.02.13 07:06
Оценка:
Здравствуйте, jazzer, Вы писали:

J>Здравствуйте, Аноним, Вы писали:


А>>Есть полиморфный массив, то есть массив указателей BaseItem*, каждый из которых реально указывает на объект какого-то класса-наследника BaseItem. Наследников много и все они образуют довольно ветвистое дерево.


А>>Нужна шаблонаня функция вида GetItem<T>(int i), которая должна сделать следующее: если реальный тип i-того элемент массива реально является классом T или наследником T (где в качестве T передается некоторый наследник BaseItem), то вернуть адрес этого объекта, иначе вернуть null.

А>>Возможно ли такое? (без буста).

J>Корректно это делается через паттерн Visitor. Шаблоны тут не помогут, так как у тебя динамика, а не статика.

Кстати тоже подумал про визитор, но тут он не нужен.
Sic luceat lux!
Re[8]: Можно ли определить, является ли тип наследником данного, на шаблонах?
От: Serg27  
Дата: 13.02.13 08:49
Оценка:
Здравствуйте, uzhas, Вы писали:

U>Здравствуйте, Serg27, Вы писали:


S>>Но это мое мнение основано на реальном баге в производственном коде.


U>я могу потелепатировать: в студии dynamic_cast указателей кидает исключение в случае, если указатель пришел из библиотеки, которая скомпилирована без поддержки rtti

U>исключение вроде имеет тип __non_rtti_object
U>про баги не слышал, а с таким поведением встречался

Телепатия на половину правильная. Поведение описано абсолютно точно . Но насчет RTTI сразу исключалось — дисциплина сборки и компиляции этого не допускала.

А баг у нас был такой. Раз в несколько месяцев программа падала. Сообщение соответствовало ("__non_rtti_object"). При повторе действий ничего не выявлялось. Именно тогда я и предположил, что это происходит из dynamic_cast который у нас применялся для проверки указателей и преобразований типов. Если ему суется невалидный указатель, то это и могло происходить. А невалидным он мог стать, например, если был произведен delete (маловероятно, так как использовали shared_ptr) или переписью мусором. Баг мы не нашли, так как была переписана подсистема, которая и так вызывала подозрения и нарекания. Он просто исчез.
Из этой истории я себе хорошо запомнил, что в dynamic_cast надо пихать только валидные указатели, иначе именно в этом месте будет выброшено исключение. В этом поведение dynamic_cast отличается от static_cast. C течением времени сама история забылась, а правило про валидные указатели и dynamic_cast в голове осталось. Еще с течением времени в голове "валидные" указатели преобразовались в "валидные" и "не нулевые". Ну вот отсюда и моя ошибка. Сейчас все в голове обновилось. thanks...
Re[3]: Можно ли определить, является ли тип наследником данного, на шаблонах?
От: jazzer Россия Skype: enerjazzer
Дата: 13.02.13 09:25
Оценка:
Здравствуйте, Kernan, Вы писали:

J>>Корректно это делается через паттерн Visitor. Шаблоны тут не помогут, так как у тебя динамика, а не статика.

K>Кстати тоже подумал про визитор, но тут он не нужен.

хз. Имхо, очень редко бывает, что надо просто узнать тип, чаще что-нть нужно со всем найденным сделать, причем условия на выполнение имеют тенденцию усложняться — вот тут-то визитор и понадобится.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[4]: Можно ли определить, является ли тип наследником данного, на шаблонах?
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 13.02.13 14:35
Оценка:
Здравствуйте, jazzer, Вы писали:

J>Здравствуйте, Kernan, Вы писали:


J>>>Корректно это делается через паттерн Visitor. Шаблоны тут не помогут, так как у тебя динамика, а не статика.

K>>Кстати тоже подумал про визитор, но тут он не нужен.

J>хз. Имхо, очень редко бывает, что надо просто узнать тип, чаще что-нть нужно со всем найденным сделать, причем условия на выполнение имеют тенденцию усложняться — вот тут-то визитор и понадобится.

А можешь сказать юзкей когда надо узнать тип и что-то с ним сделать? Не правильнее ли просто сделать виртуальные методы и не узнавать тип либо использовать двойную диспетчеризацию, к примеру?
Sic luceat lux!
Re[2]: Можно ли определить, является ли тип наследником данного, на шаблонах?
От: Vamp Россия  
Дата: 13.02.13 16:00
Оценка: +1
J>Корректно это делается через паттерн Visitor. Шаблоны тут не помогут, так как у тебя динамика, а не статика.
А почему через визитер, а не просто виртуальными функциями?
Да здравствует мыло душистое и веревка пушистая.
Re[9]: Можно ли определить, является ли тип наследником данного, на шаблонах?
От: Erop Россия  
Дата: 13.02.13 17:25
Оценка:
Здравствуйте, Serg27, Вы писали:

S>Из этой истории я себе хорошо запомнил, что в dynamic_cast надо пихать только валидные указатели, иначе именно в этом месте будет выброшено исключение. В этом поведение dynamic_cast отличается от static_cast.


Не совсем так.
Во-первых, формально, в С++ с невалидными указателями много чего нельзя делать, например копировать их небезопасно.
Но это всё теоретические несколько UB, что же касается практики, то опасно преобразовывать мусорные указатели такого типа, для преобразований которых надо лезть в данные.
А это не только RTTI, но и преобразования к от виртуальной базы, например
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: Можно ли определить, является ли тип наследником данного, на шаблонах?
От: jazzer Россия Skype: enerjazzer
Дата: 13.02.13 17:54
Оценка: +1 -1
Здравствуйте, Vamp, Вы писали:

J>>Корректно это делается через паттерн Visitor. Шаблоны тут не помогут, так как у тебя динамика, а не статика.

V>А почему через визитер, а не просто виртуальными функциями?

визитер — это, можно сказать, внешняя виртуальная функция.

С нормальными виртуальными функциями ты всю функциональность вставляешь прямо в классы иерархии, даже если они там не нужны (по Single Responsibility Principle, например), а нужны лишь в одном только месте программы.
Т.е. представь, что тебе надо как-то хитро распечатывать объекты, причем в 10 разных местах программы это нужно делать по-разному (и только в этих местах, т.е. reuse=0). С виртуальными функциями тебе придется сделать все эти 10 функций прямо в классах, несмотря на то, что каждая будет зваться ровно в одном месте программы — это ж ужас.

С визиторами же ты можешь наделать сколько угодно разнообразных визиторов, каждый из которых будет локальным в данном месте программы, и это не потребует изменения классов иерархии.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[5]: Можно ли определить, является ли тип наследником данного, на шаблонах?
От: jazzer Россия Skype: enerjazzer
Дата: 13.02.13 17:55
Оценка:
Здравствуйте, Kernan, Вы писали:

K>А можешь сказать юзкей когда надо узнать тип и что-то с ним сделать? Не правильнее ли просто сделать виртуальные методы и не узнавать тип либо использовать двойную диспетчеризацию, к примеру?


Про виртуальные фукнции я уже рядом ответил (и юзкейс там же), а про двойную диспетчеризацию — так визитер этим и занимается.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.