Здравствуйте, 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> virtualMyParameter * Clone() const { return new MyParameter(*this); }
C> // other field and methods
C>};
C>
C>...
Для типов возвращаемых значений в случае с виртуальными методами в стандарте есть послабление которое позволяет писать так (выделено жирным). Иногда это может быть полезным.
Здравствуйте, 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 derrivedvirtual 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 derrivedvirtual IParameter * Clone() const { return new MyParameter(*this); }
// other field and methods
};
IParameter *param;
my_form_notification_handler(param->Clone());
кстати, в твоём и без того неправильном примере неправильно освобождается память...
delete[] param;
Здравствуйте, Dsmover, Вы писали:
D>Здравствуйте, Caracrist, Вы писали:
C>>memory leak C>>нет такого понятия: "delete делать не надо никому"
D>как так нету
oк расскажу.
в Clone() создаётся объект; указатель на память в которой он находится возвращается из функции. Передавая значение объекта по ссылке(by reference) ты ничего не меняешь. Затем ты обратно получаешь указатель и передаёшь его дальше. Ссылка разрушиться при выходе из функции никак не затронув объект. И если там где ты получил указатель, не будет сделано освобождение памяти, то она останется просто потеряной. Это и есть memory leak.
В целом на каждый new должен быть вызван delete.
Исключением явлаeтся placement new.
Здравствуйте, Dsmover, Вы писали:
D>Еще маленький вопрос почти по теме. D>Вот есть класс IParameter. Есть наследники от него. D>Я хочу в один и тот же обработчик передавать скажем 5 разных наследников (то есть бывает 5 разных сущностей параметров). D>Как в этом обработчике лучше проверять, какой конкретный пришел параметер:
Сперва нужно ответить — ЗАЧЕМ проверять, какой конкретный параметр.
Можно ли решить задачу с помощью виртуальных функций? Пусть каждый наследник умеет по-своему делать ту задачу, которую ты на него взваливаешь. Выдели эту задачу в отдельную функцию-член интерфейса и дёргай.
Виртуальные вызовы — точно дешевле и свитча с динамик-кастами, и последовательных динамик-кастов.
Вариант со свитчом некрасив потому, что ты задействуешь параллельно сразу два RTTI — штатный (dynamic_cast) и самодельный (GetIdParam).
Нужны веские основания для того, чтобы писать самодельный RTTI (например, если идентификаторы прописаны в техническом задании, как неотъемлемая часть предметной области; или, когда требуется ABI с другими языками, что-то вроде COM; но тогда не нужен штатный RTTI, пользуйся только самодельным).
Хочется передавать в функцию переменную любого типа, но не выходит. Реализация нужна без шаблонов.
Как я делаю — есть базовый класс 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;
}
Здравствуйте, 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;
Здравствуйте, 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 разных сущностей параметров).
Как в этом обработчике лучше проверять, какой конкретный пришел параметер:
Кстати а зачем собственно клонировать сам объект. По идее нам нужно клонировать указатель.
Объект Parameter* он размещен же не в стеке, а в куче и этот указатель валиден для всех потоков в рамках процесса.
Соответствено клон по идее достаточно сделать указателю а не всем данным объекта.
Здравствуйте, 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>
Интересно, запомню.
Но
Объект как раз лежит в стеке, а создавать его динамически совсем не хочется
Здравствуйте, Dsmover, Вы писали:
D>Теперь, внимание, вопрос! D>Я передаю параметры из одного треда в другой. Поэтому я не могу дать указатель на полиморфный класс (в другом потоке этот объект уже исчезнет из стека).
Почему? В одном потоке выделяешь память для объекта через new и передаешь указатель в метод другого потока, тот поработав с указателем на объект, уничтожает его delete'ом. Зачем клонировать?
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, 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).
Хочется использовать какой-то новый безопасный С++-ый подход.
Здравствуйте, Logot, Вы писали:
L>Здравствуйте, Dsmover, Вы писали:
D>>Теперь, внимание, вопрос! D>>Я передаю параметры из одного треда в другой. Поэтому я не могу дать указатель на полиморфный класс (в другом потоке этот объект уже исчезнет из стека).
L>Почему? В одном потоке выделяешь память для объекта через new и передаешь указатель в метод другого потока, тот поработав с указателем на объект, уничтожает его delete'ом. Зачем клонировать?
Не люблю я такие new: в одном месте new, а delete в совсем другом. Не хочу
Эту прогу пишут 4 человека. Кто-то напортачит потрогав мой код, и забыв убрать там delete в другом месте. а притензии ко мне будут
Здравствуйте, Dsmover, Вы писали:
D>Не люблю я такие new: в одном месте new, а delete в совсем другом. Не хочу
D>Эту прогу пишут 4 человека. Кто-то напортачит потрогав мой код, и забыв убрать там delete в другом месте. а притензии ко мне будут
Здравствуйте, Dsmover, Вы писали:
D> Я хочу передавать разные параметры, в одном случае просто число, иногда строка, иногда структура и т.д, смотря что ждет обработчик при каком событии. Сам класс (наследник от IParameter) является в принципе только хранилищем разного рода данных.
Тогда можно сосредоточиться на вариантных типах в отрыве от объектно-ориентированности (зачем нам лишние сущности?)
Если есть возможность и желание припахать буст, то см. boost::variant и boost::any
Если нужен стандартизованный интерфейс со сторонними модулями, то см. COM VARIANT и его С++ные обёртки (MSVC _variant_t, ATL::CComVariant)
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, Dsmover, Вы писали:
D>> Я хочу передавать разные параметры, в одном случае просто число, иногда строка, иногда структура и т.д, смотря что ждет обработчик при каком событии. Сам класс (наследник от IParameter) является в принципе только хранилищем разного рода данных.
К>Тогда можно сосредоточиться на вариантных типах в отрыве от объектно-ориентированности (зачем нам лишние сущности?) К>Если есть возможность и желание припахать буст, то см. boost::variant и boost::any К>Если нужен стандартизованный интерфейс со сторонними модулями, то см. COM VARIANT и его С++ные обёртки (MSVC _variant_t, ATL::CComVariant)
boost нет желания тащить. я здесь не один в проекте, да и не хочется.
Какой COM и ATL, мы пишем в брутальном и волшебном мире Linux-a
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, Dsmover, Вы писали:
D>> Я хочу передавать разные параметры, в одном случае просто число, иногда строка, иногда структура и т.д, смотря что ждет обработчик при каком событии. Сам класс (наследник от IParameter) является в принципе только хранилищем разного рода данных.
К>Тогда можно сосредоточиться на вариантных типах в отрыве от объектно-ориентированности (зачем нам лишние сущности?) К>Если есть возможность и желание припахать буст, то см. boost::variant и boost::any К>Если нужен стандартизованный интерфейс со сторонними модулями, то см. COM VARIANT и его С++ные обёртки (MSVC _variant_t, ATL::CComVariant)
Да и Вариант это слабая тема. Она поддерживает все существующие типы (смотрел реализацию QVariant в сырцах QT). А мне надо "запихивать" разные структуры, классы, массивы объектов...
Здравствуйте, Dsmover, Вы писали:
D>Да и Вариант это слабая тема. Она поддерживает все существующие типы (смотрел реализацию QVariant в сырцах QT). А мне надо "запихивать" разные структуры, классы, массивы объектов...
Здравствуйте, Finder_b, Вы писали:
F_>Здравствуйте, Dsmover, Вы писали:
D>>Да и Вариант это слабая тема. Она поддерживает все существующие типы (смотрел реализацию QVariant в сырцах QT). А мне надо "запихивать" разные структуры, классы, массивы объектов...
F_>Может boost::any подойдет?
Здравствуйте, Dsmover, Вы писали:
F_>>Может boost::any подойдет?
D>не хочу и не имею права тащить буст
скопируй (переименовав буковки)
там простая реализация
Здравствуйте, Dsmover, Вы писали:
D>Да и Вариант это слабая тема. Она поддерживает все существующие типы (смотрел реализацию QVariant в сырцах QT). А мне надо "запихивать" разные структуры, классы, массивы объектов...
Чую, что здесь какая-то архитектурная проблема...
Вообще, по-хорошему: либо функция твёрдо знает, с каким типом работает, и тогда незачем ветвиться; либо не знает и знать не желает — просто передаёт данные в коробке как есть.
Исключений не так уж много: это маршаллинг, сериализация, распечатка.
Здравствуйте, ankf, Вы писали:
A>Кстати а зачем собственно клонировать сам объект. По идее нам нужно клонировать указатель. A>Объект Parameter* он размещен же не в стеке, а в куче и этот указатель валиден для всех потоков в рамках процесса.
размещение объекта ТОЛЬКО в куче надо еще гарантировать специальным образом...