Re[2]: dynamic_cast RTTI проблема
От: Arsenicum Россия  
Дата: 14.05.10 05:22
Оценка: 12 (4)
Здравствуйте, Caracrist, Вы писали:

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

C>...
C>Классика...
C>
C>class IParameter
C>{
C>  public:
C>    IParameter(const IParameter&); // Copy constructor must be defined for all derrived
C>    virtual IParameter * Clone() const { return new IParameter(*this); }

C>  // other field and methods
C>};

C>class MyParameter : public IParameter
C>{
C>  public:
C>    MyParameter(const MyParameter&); // Copy constructor must be defined for all derrived
C>    virtual MyParameter * Clone() const { return new MyParameter(*this); }

C>  // other field and methods
C>};
C>

C>...

Для типов возвращаемых значений в случае с виртуальными методами в стандарте есть послабление которое позволяет писать так (выделено жирным). Иногда это может быть полезным.
Re[2]: dynamic_cast RTTI проблема
От: Dsmover  
Дата: 13.05.10 16:01
Оценка: -3
Здравствуйте, Caracrist, Вы писали:

C>IParameter *param;
C>my_form_notification_handler(param->Clone());
C>


Можно даже чуть улучшить:
IParameter *param;
IParameter &p = *(param->Clone());
my_form_notification_handler(&p);


Так delete делать не надо никому...
Re[6]: dynamic_cast RTTI проблема
От: Centaur Россия  
Дата: 14.05.10 05:49
Оценка: 3 (1) +1
Здравствуйте, Caracrist, Вы писали:

C>В целом на каждый new должен быть вызван delete.

C>Исключением явлаeтся placement new.

Зато на каждый placement new, по-хорошему, должен быть сделан явный вызов деструктора. Иначе какие-нибудь внутренности всё равно утекут.
Re: dynamic_cast RTTI проблема
От: Caracrist https://1pwd.org/
Дата: 13.05.10 15:31
Оценка: 3 (1)
Здравствуйте, Dsmover, Вы писали:

D>Хочется передавать в функцию переменную любого типа, но не выходит. Реализация нужна без шаблонов.

D>Как я делаю — есть базовый класс IParameter, а от него есть наследники.

D>В функцию notify(IParamter* param) передаю наследника UpdateLabelValue. А там внутри через dynamic_cast все разруливаю. Это работает.


D>Теперь, внимание, вопрос!

D>Я передаю параметры из одного треда в другой. Поэтому я не могу дать указатель на полиморфный класс (в другом потоке этот объект уже исчезнет из стека). Приходится делать как-то копию класса наследника по указателю класса предка и делитить память.

Классика...
class IParameter
{
  public:
    IParameter(const IParameter&); // Copy constructor must be defined for all derrived
    virtual IParameter * Clone() const { return new IParameter(*this); }

  // other field and methods
};

class MyParameter : public IParameter
{
  public:
    MyParameter(const MyParameter&); // Copy constructor must be defined for all derrived
    virtual IParameter * Clone() const { return new MyParameter(*this); }

  // other field and methods
};


IParameter *param;
my_form_notification_handler(param->Clone());


кстати, в твоём и без того неправильном примере неправильно освобождается память...
delete[] param;
~~~~~
~lol~~
~~~ Single Password Solution
Re[5]: dynamic_cast RTTI проблема
От: Caracrist https://1pwd.org/
Дата: 13.05.10 16:26
Оценка: 3 (1)
Здравствуйте, Dsmover, Вы писали:

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


C>>memory leak

C>>нет такого понятия: "delete делать не надо никому"

D>как так нету


oк расскажу.

в Clone() создаётся объект; указатель на память в которой он находится возвращается из функции. Передавая значение объекта по ссылке(by reference) ты ничего не меняешь. Затем ты обратно получаешь указатель и передаёшь его дальше. Ссылка разрушиться при выходе из функции никак не затронув объект. И если там где ты получил указатель, не будет сделано освобождение памяти, то она останется просто потеряной. Это и есть memory leak.

В целом на каждый new должен быть вызван delete.
Исключением явлаeтся placement new.
~~~~~
~lol~~
~~~ Single Password Solution
Re[7]: dynamic_cast RTTI проблема
От: Кодт Россия  
Дата: 14.05.10 13:43
Оценка: 3 (1)
Здравствуйте, Dsmover, Вы писали:

D>Еще маленький вопрос почти по теме.

D>Вот есть класс IParameter. Есть наследники от него.
D>Я хочу в один и тот же обработчик передавать скажем 5 разных наследников (то есть бывает 5 разных сущностей параметров).
D>Как в этом обработчике лучше проверять, какой конкретный пришел параметер:

Сперва нужно ответить — ЗАЧЕМ проверять, какой конкретный параметр.
Можно ли решить задачу с помощью виртуальных функций? Пусть каждый наследник умеет по-своему делать ту задачу, которую ты на него взваливаешь. Выдели эту задачу в отдельную функцию-член интерфейса и дёргай.
Виртуальные вызовы — точно дешевле и свитча с динамик-кастами, и последовательных динамик-кастов.

Вариант со свитчом некрасив потому, что ты задействуешь параллельно сразу два RTTI — штатный (dynamic_cast) и самодельный (GetIdParam).
Нужны веские основания для того, чтобы писать самодельный RTTI (например, если идентификаторы прописаны в техническом задании, как неотъемлемая часть предметной области; или, когда требуется ABI с другими языками, что-то вроде COM; но тогда не нужен штатный RTTI, пользуйся только самодельным).
Перекуём баги на фичи!
Re: dynamic_cast RTTI проблема
От: XuMuK Россия  
Дата: 13.05.10 15:24
Оценка: +1
Здравствуйте, Dsmover, Вы писали:


D>void __UserNotification(IParameter *param, int size)

D>{
D> void *p = new char[size]; // спасите!!!!!!!!!!!!!!!!!!!!!!!!!!
D> memcpy(p, param, size); // чем это заменить???????????????

D> my_form_notification_handler((IParameter *)p);

D>}

добавить в интерфейс IParameter виртуальный метод IParameter* Clone() который будет по умолчанию возвращать 0, например?
dynamic_cast RTTI проблема
От: Dsmover  
Дата: 13.05.10 15:15
Оценка:
Хочется передавать в функцию переменную любого типа, но не выходит. Реализация нужна без шаблонов.
Как я делаю — есть базовый класс IParameter, а от него есть наследники.

В функцию notify(IParamter* param) передаю наследника UpdateLabelValue. А там внутри через dynamic_cast все разруливаю. Это работает.

Теперь, внимание, вопрос!
Я передаю параметры из одного треда в другой. Поэтому я не могу дать указатель на полиморфный класс (в другом потоке этот объект уже исчезнет из стека). Приходится делать как-то копию класса наследника по указателю класса предка и делитить память.

Вот моя ужасная реализация:

void my_form_notification_handler(IParameter *param)                                                                                                         
{                                                                                                                                                            
  try {                                                                                                                                                      
    UpdateLabelValue& m = dynamic_cast<UpdateLabelValue&>(*param);                                                                                           
    int val =   m.GetValue();                                                                                                                                  
    printf("parameter is: int value: %i\n", val);                                                                                                            
  } catch (const std::bad_cast& e) {                                                                                                                         
    std::cerr << e.what() << std::endl;                                                                                                                      
    std::cerr << "Этот объект не является объектом типа UpdateLabelValue" << std::endl;                                                                      
  }
  delete param;                                                                                                                                                          
}                                                                                                                                                            
                                                                                                                                                             
void __UserNotification(IParameter *param, int size)                                                                                                         
{                                                                                                                                                            
  void *p = new char[size]; // спасите!!!!!!!!!!!!!!!!!!!!!!!!!!
  memcpy(p, param, size); // чем это заменить???????????????
                                                                                                                                                           
  my_form_notification_handler((IParameter *)p);                                                                                                             
}                                                                                                                                                            
                                                                                                                                                             
#define UserNotification(p) __UserNotification(&p, sizeof(p));                                                                                               
                                                                                                                                                             
int main()                                                                                                                                                   
{                                                                                                                                                     
  UpdateLabelValue m(45);                                                                                                                                    
  UserNotification(m);                                                                                                                                       
  return 0;                                                                                                                                                  
}
Re: dynamic_cast RTTI проблема
От: _stun_ Россия  
Дата: 13.05.10 15:30
Оценка:
Погуглить про виртуальный конструктор и выбрать реализацию на свой вкус.
Re[2]: dynamic_cast RTTI проблема
От: _stun_ Россия  
Дата: 13.05.10 15:32
Оценка:
Здравствуйте, _stun_, Вы писали:

__>Погуглить про виртуальный конструктор и выбрать реализацию на свой вкус.


Тем более, что одну из возможных реализаций уже подсказали
Re[2]: dynamic_cast RTTI проблема
От: Dsmover  
Дата: 13.05.10 15:38
Оценка:
Здравствуйте, Caracrist, Вы писали:

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


D>>Хочется передавать в функцию переменную любого типа, но не выходит. Реализация нужна без шаблонов.

D>>Как я делаю — есть базовый класс IParameter, а от него есть наследники.

D>>В функцию notify(IParamter* param) передаю наследника UpdateLabelValue. А там внутри через dynamic_cast все разруливаю. Это работает.


D>>Теперь, внимание, вопрос!

D>>Я передаю параметры из одного треда в другой. Поэтому я не могу дать указатель на полиморфный класс (в другом потоке этот объект уже исчезнет из стека). Приходится делать как-то копию класса наследника по указателю класса предка и делитить память.

C>Классика...

C>
C>class IParameter
C>{
C>  public:
C>    IParameter(const IParameter&); // Copy constructor must be defined for all derrived
C>    virtual IParameter * Clone() const { return new IParameter(*this); }

C>  // other field and methods
C>};

C>class MyParameter : public IParameter
C>{
C>  public:
C>    MyParameter(const MyParameter&); // Copy constructor must be defined for all derrived
C>    virtual IParameter * Clone() const { return new MyParameter(*this); }

C>  // other field and methods
C>};


C>IParameter *param;
C>my_form_notification_handler(param->Clone());
C>


C>кстати, в твоём и без того неправильном примере неправильно освобождается память...

C>delete[] param;

я и сказал, что это отвратительная реализация
Re[2]: dynamic_cast RTTI проблема
От: Dsmover  
Дата: 13.05.10 15:49
Оценка:
Здравствуйте, Caracrist, Вы писали:

<skipped>

Работает! Большое человеческое спасибо!

Хотя, если конструктор "копирования по умолчанию" подходит... Вообщем, какой-то лишний огород городится. Язык Си++ мог бы быть и лаконичей!
Re[3]: dynamic_cast RTTI проблема
От: Caracrist https://1pwd.org/
Дата: 13.05.10 16:14
Оценка:
Здравствуйте, Dsmover, Вы писали:

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


D>
C>>IParameter *param;
C>>my_form_notification_handler(param->Clone());
C>>


D>Можно даже чуть улучшить:

D>
D>IParameter *param;
D>IParameter &p = *(param->Clone());
D>my_form_notification_handler(&p);
D>


D>Так delete делать не надо никому...


memory leak
нет такого понятия: "delete делать не надо никому"
~~~~~
~lol~~
~~~ Single Password Solution
Re[4]: dynamic_cast RTTI проблема
От: Dsmover  
Дата: 13.05.10 16:18
Оценка:
Здравствуйте, Caracrist, Вы писали:

C>memory leak

C>нет такого понятия: "delete делать не надо никому"

как так нету
Re[6]: dynamic_cast RTTI проблема
От: Dsmover  
Дата: 14.05.10 12:58
Оценка:
Здравствуйте, Caracrist, Вы писали:

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


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


C>>>memory leak

C>>>нет такого понятия: "delete делать не надо никому"

D>>как так нету


C>oк расскажу.


C>в Clone() создаётся объект; указатель на память в которой он находится возвращается из функции. Передавая значение объекта по ссылке(by reference) ты ничего не меняешь. Затем ты обратно получаешь указатель и передаёшь его дальше. Ссылка разрушиться при выходе из функции никак не затронув объект. И если там где ты получил указатель, не будет сделано освобождение памяти, то она останется просто потеряной. Это и есть memory leak.


C>В целом на каждый new должен быть вызван delete.

C>Исключением явлаeтся placement new.

Спасибо за ответы. Действительно утечка памяти... Придется умный указатель воткнуть либо аккуратно работать.

placement new — знаю такую фишку, правда никогда еще не возникала необходимость ее использовать
Явный вызов деструктора попробовал сегодня поделать — это жесть, вот так синтаксис

Еще маленький вопрос почти по теме.
Вот есть класс IParameter. Есть наследники от него.
Я хочу в один и тот же обработчик передавать скажем 5 разных наследников (то есть бывает 5 разных сущностей параметров).
Как в этом обработчике лучше проверять, какой конкретный пришел параметер:

Так:

IParamter *p;
Parameter1 *p1 = dynamic_cast<MyParameter1>(p);
if (p1) { ...; return; }
Parameter2 *p2 = dynamic_cast<MyParameter2>(p);
if (p2) { ...; return; }



Или:

IParameter *p;
int param_id = p->GetIdParam();
switch (param_id)
{
  case 1: Parameter1 *p1 = dynamic_cast<MyParameter1>(p);
    break;
  case 2: Parameter2 *p2 = dynamic_cast<MyParameter2>(p);
}



Второй случай вроде бы должен быстрее работать (нет переборов кастов), но с другой стороны и нафиг тут RTTI с dynamic_cast и всего преимущества
Re[2]: dynamic_cast RTTI проблема
От: ankf  
Дата: 14.05.10 13:55
Оценка:
Здравствуйте, Caracrist, Вы писали:




C>IParameter *param;

C>my_form_notification_handler(param->Clone());
C>[/ccode]

Кстати а зачем собственно клонировать сам объект. По идее нам нужно клонировать указатель.
Объект Parameter* он размещен же не в стеке, а в куче и этот указатель валиден для всех потоков в рамках процесса.

Соответствено клон по идее достаточно сделать указателю а не всем данным объекта.

Как то так

class TradeSafeClone<T>
{
   T* m_pointer;

   TreadSafeClone( T* pointer )
   {
       m_pointer = pointer;
   }

   T* Clone()
   {
        return m_pointer;
   }
}
Я программист, я Иван Помидоров, хватить трепатся — наш козырь error.
Re[3]: dynamic_cast RTTI проблема
От: Dsmover  
Дата: 14.05.10 14:16
Оценка:
Здравствуйте, ankf, Вы писали:

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





C>>IParameter *param;

C>>my_form_notification_handler(param->Clone());
C>>[/ccode]

A>Кстати а зачем собственно клонировать сам объект. По идее нам нужно клонировать указатель.

A>Объект Parameter* он размещен же не в стеке, а в куче и этот указатель валиден для всех потоков в рамках процесса.

A>Соответствено клон по идее достаточно сделать указателю а не всем данным объекта.


A>Как то так

A>

A>class TradeSafeClone<T>
A>{
A>   T* m_pointer;

A>   TreadSafeClone( T* pointer )
A>   {
A>       m_pointer = pointer;
A>   }

A>   T* Clone()
A>   {
A>        return m_pointer;
A>   }
A>}
A>


Интересно, запомню.
Но
Объект как раз лежит в стеке, а создавать его динамически совсем не хочется
Re: dynamic_cast RTTI проблема
От: Logot Украина  
Дата: 14.05.10 14:23
Оценка:
Здравствуйте, Dsmover, Вы писали:

D>Теперь, внимание, вопрос!

D>Я передаю параметры из одного треда в другой. Поэтому я не могу дать указатель на полиморфный класс (в другом потоке этот объект уже исчезнет из стека).

Почему? В одном потоке выделяешь память для объекта через new и передаешь указатель в метод другого потока, тот поработав с указателем на объект, уничтожает его delete'ом. Зачем клонировать?
Re[8]: dynamic_cast RTTI проблема
От: Dsmover  
Дата: 14.05.10 14:29
Оценка:
Здравствуйте, Кодт, Вы писали:

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


D>>Еще маленький вопрос почти по теме.

D>>Вот есть класс IParameter. Есть наследники от него.
D>>Я хочу в один и тот же обработчик передавать скажем 5 разных наследников (то есть бывает 5 разных сущностей параметров).
D>>Как в этом обработчике лучше проверять, какой конкретный пришел параметер:

К>Сперва нужно ответить — ЗАЧЕМ проверять, какой конкретный параметр.

К>Можно ли решить задачу с помощью виртуальных функций? Пусть каждый наследник умеет по-своему делать ту задачу, которую ты на него взваливаешь. Выдели эту задачу в отдельную функцию-член интерфейса и дёргай.
К>Виртуальные вызовы — точно дешевле и свитча с динамик-кастами, и последовательных динамик-кастов.

К>Вариант со свитчом некрасив потому, что ты задействуешь параллельно сразу два RTTI — штатный (dynamic_cast) и самодельный (GetIdParam).

К>Нужны веские основания для того, чтобы писать самодельный RTTI (например, если идентификаторы прописаны в техническом задании, как неотъемлемая часть предметной области; или, когда требуется ABI с другими языками, что-то вроде COM; но тогда не нужен штатный RTTI, пользуйся только самодельным).

Я хочу передавать разные параметры, в одном случае просто число, иногда строка, иногда структура и т.д, смотря что ждет обработчик при каком событии. Сам класс (наследник от IParameter) является в принципе только хранилищем разного рода данных.
Поясню зачем я все это спрашиваю... Идеалогия MFC SendMessage(hWnd, WM_USER + n, (DWORD) &cstring_str, (DWORD) int_value) мне не нравится кривотой и небезопасностью разбора кастами реальных параметров в WndProc(DWORD lParam, wParam).
Хочется использовать какой-то новый безопасный С++-ый подход.
Re[2]: dynamic_cast RTTI проблема
От: Dsmover  
Дата: 14.05.10 14:33
Оценка:
Здравствуйте, Logot, Вы писали:

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


D>>Теперь, внимание, вопрос!

D>>Я передаю параметры из одного треда в другой. Поэтому я не могу дать указатель на полиморфный класс (в другом потоке этот объект уже исчезнет из стека).

L>Почему? В одном потоке выделяешь память для объекта через new и передаешь указатель в метод другого потока, тот поработав с указателем на объект, уничтожает его delete'ом. Зачем клонировать?


Не люблю я такие new: в одном месте new, а delete в совсем другом. Не хочу

Эту прогу пишут 4 человека. Кто-то напортачит потрогав мой код, и забыв убрать там delete в другом месте. а притензии ко мне будут
Re[3]: dynamic_cast RTTI проблема
От: Logot Украина  
Дата: 14.05.10 14:46
Оценка:
Здравствуйте, Dsmover, Вы писали:

D>Не люблю я такие new: в одном месте new, а delete в совсем другом. Не хочу


D>Эту прогу пишут 4 человека. Кто-то напортачит потрогав мой код, и забыв убрать там delete в другом месте. а притензии ко мне будут


smart_ptr?
Re[9]: dynamic_cast RTTI проблема
От: Кодт Россия  
Дата: 14.05.10 15:56
Оценка:
Здравствуйте, Dsmover, Вы писали:

D> Я хочу передавать разные параметры, в одном случае просто число, иногда строка, иногда структура и т.д, смотря что ждет обработчик при каком событии. Сам класс (наследник от IParameter) является в принципе только хранилищем разного рода данных.


Тогда можно сосредоточиться на вариантных типах в отрыве от объектно-ориентированности (зачем нам лишние сущности?)
Если есть возможность и желание припахать буст, то см. boost::variant и boost::any
Если нужен стандартизованный интерфейс со сторонними модулями, то см. COM VARIANT и его С++ные обёртки (MSVC _variant_t, ATL::CComVariant)
Перекуём баги на фичи!
Re[10]: dynamic_cast RTTI проблема
От: Dsmover  
Дата: 14.05.10 16:01
Оценка:
Здравствуйте, Кодт, Вы писали:

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


D>> Я хочу передавать разные параметры, в одном случае просто число, иногда строка, иногда структура и т.д, смотря что ждет обработчик при каком событии. Сам класс (наследник от IParameter) является в принципе только хранилищем разного рода данных.


К>Тогда можно сосредоточиться на вариантных типах в отрыве от объектно-ориентированности (зачем нам лишние сущности?)

К>Если есть возможность и желание припахать буст, то см. boost::variant и boost::any
К>Если нужен стандартизованный интерфейс со сторонними модулями, то см. COM VARIANT и его С++ные обёртки (MSVC _variant_t, ATL::CComVariant)

boost нет желания тащить. я здесь не один в проекте, да и не хочется.
Какой COM и ATL, мы пишем в брутальном и волшебном мире Linux-a
Re[10]: dynamic_cast RTTI проблема
От: Dsmover  
Дата: 14.05.10 16:04
Оценка:
Здравствуйте, Кодт, Вы писали:

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


D>> Я хочу передавать разные параметры, в одном случае просто число, иногда строка, иногда структура и т.д, смотря что ждет обработчик при каком событии. Сам класс (наследник от IParameter) является в принципе только хранилищем разного рода данных.


К>Тогда можно сосредоточиться на вариантных типах в отрыве от объектно-ориентированности (зачем нам лишние сущности?)

К>Если есть возможность и желание припахать буст, то см. boost::variant и boost::any
К>Если нужен стандартизованный интерфейс со сторонними модулями, то см. COM VARIANT и его С++ные обёртки (MSVC _variant_t, ATL::CComVariant)

Да и Вариант это слабая тема. Она поддерживает все существующие типы (смотрел реализацию QVariant в сырцах QT). А мне надо "запихивать" разные структуры, классы, массивы объектов...
Re[11]: dynamic_cast RTTI проблема
От: Finder_b  
Дата: 14.05.10 16:18
Оценка:
Здравствуйте, Dsmover, Вы писали:

D>Да и Вариант это слабая тема. Она поддерживает все существующие типы (смотрел реализацию QVariant в сырцах QT). А мне надо "запихивать" разные структуры, классы, массивы объектов...


Может boost::any подойдет?
Re[12]: dynamic_cast RTTI проблема
От: Dsmover  
Дата: 14.05.10 16:28
Оценка:
Здравствуйте, Finder_b, Вы писали:

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


D>>Да и Вариант это слабая тема. Она поддерживает все существующие типы (смотрел реализацию QVariant в сырцах QT). А мне надо "запихивать" разные структуры, классы, массивы объектов...


F_>Может boost::any подойдет?


не хочу и не имею права тащить буст
Re[13]: dynamic_cast RTTI проблема
От: uzhas Ниоткуда  
Дата: 14.05.10 16:50
Оценка:
Здравствуйте, Dsmover, Вы писали:

F_>>Может boost::any подойдет?


D>не хочу и не имею права тащить буст

скопируй (переименовав буковки)
там простая реализация
Re[11]: dynamic_cast RTTI проблема
От: Кодт Россия  
Дата: 14.05.10 17:18
Оценка:
Здравствуйте, Dsmover, Вы писали:

D>Да и Вариант это слабая тема. Она поддерживает все существующие типы (смотрел реализацию QVariant в сырцах QT). А мне надо "запихивать" разные структуры, классы, массивы объектов...


Чую, что здесь какая-то архитектурная проблема...

Вообще, по-хорошему: либо функция твёрдо знает, с каким типом работает, и тогда незачем ветвиться; либо не знает и знать не желает — просто передаёт данные в коробке как есть.
Исключений не так уж много: это маршаллинг, сериализация, распечатка.
Перекуём баги на фичи!
Re[3]: dynamic_cast RTTI проблема
От: mike_rs Россия  
Дата: 17.05.10 13:00
Оценка:
Здравствуйте, ankf, Вы писали:

A>Кстати а зачем собственно клонировать сам объект. По идее нам нужно клонировать указатель.

A>Объект Parameter* он размещен же не в стеке, а в куче и этот указатель валиден для всех потоков в рамках процесса.

размещение объекта ТОЛЬКО в куче надо еще гарантировать специальным образом...
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.