powered by simpleCommunicator - 2.0.59     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / C++ [игнор отключен] [закрыт для гостей] / Как вызвать деструктор не зная тип объекта?
25 сообщений из 25, страница 1 из 1
Как вызвать деструктор не зная тип объекта?
    #39421743
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Продолжение этой темы .
Упрощенный пример
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
struct A {
	int x = 0;

	A() {
		printf("constructor\n");
		x = 1;
	}

	~A() {
		printf("destructor\n");
	}

	void print() {
		printf("x = %d\n", x);
	}
};


template <typename T>
void* create() {
	printf("create()\n");
	void* msg = malloc(sizeof(size_t) + sizeof(T));
	void* ptr = (((size_t*)msg)+1);
	new (ptr) T(); // Конструктор
	return msg;
}

template <typename T>
T* get(void* msg) {
	printf("get()\n");
	return (T*)(((size_t*)msg) + 1);
}

void erase(void* msg) {
	void* ptr = (((size_t*)msg) + 1);
	// Тут надо как-то сделать delete ptr;
}

int main() {
	void* m = create<A>();
	A* d = get<A>(m);
	d->print();
	return 0;
}


Пытаюсь сделать сообщение полноценным объектом. Вызвать конструктор не проблема, проблема с деструктором.
Проблема в том что память под сообщением очищается библиотекой, а для нее содержимое это void*, как тут быть с деструктором?

Может как-то можно извернуться на шаблонах и адрес деструктора изначально сохранить при создании сообщения в create<T>(), а в erase() просто его вызвать?
Может еще какие-то способы есть?
...
Рейтинг: 0 / 0
Как вызвать деструктор не зная тип объекта?
    #39421892
Siemargl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T,

Или крестик снять или трусы надеть.

Либо ты делаешь полноценный объект с виртуальным деструктором либо типизированный обработчик на шаблонах (можно чтобы базовый <Т> умел удалять всё содержимое единым куском).

Есть еще подвариант - память под сообщение выделять одним цельным куском и удалится оно средствами аллокатора. Тогда никаких конструкторов.
...
Рейтинг: 0 / 0
Как вызвать деструктор не зная тип объекта?
    #39421907
Barlone
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TМожет как-то можно извернуться на шаблонах и адрес деструктора изначально сохранить при создании сообщения в create<T>(), а в erase() просто его вызвать?
Можно конечно. Сделайте вместо шаблонных функций шаблонный класс со статическими методами, и в нем же функцию очистки, вызывающую деструктор.
...
Рейтинг: 0 / 0
Как вызвать деструктор не зная тип объекта?
    #39421914
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SiemarglDima T,

Или крестик снять или трусы надеть.
Я и то и другое готов сделать, только как?

SiemarglЛибо ты делаешь полноценный объект с виртуальным деструктором либо типизированный обработчик на шаблонах (можно чтобы базовый <Т> умел удалять всё содержимое единым куском).

Есть еще подвариант - память под сообщение выделять одним цельным куском и удалится оно средствами аллокатора. Тогда никаких конструкторов.
Я гоняю сообщения, точнее указатели на них, между обработчиками сообщений, причем типы мне неизвестны, я либа, но часть этой либы это удаление сообщений, т.е. освобождение памяти. Типизацию я сделал c помощью контроля typeid(T).hash_code(), который в сообщение пишется при создании.

Сделать полноценные типизированные сообщения вообще не вариант: один обработчик может получать несколько типов сообщений. Для либы без разницы какие типы, главное доставить их в порядке отправления, т.е. очередь из разных типов. Можно конечно классическое наследование, т.е. базовый класс my_msg_t и гонять указатель на него, но я тут теряю простоту написания кода, я не смогу сделать сообщение из std::string или std::vector, я буду вынужден объявить класс производный от my_msg_t где внутри будет std::string. Кроме лишних букав в коде это еще лишний тормоз в виде вызова виртуальных методов.
...
Рейтинг: 0 / 0
Как вызвать деструктор не зная тип объекта?
    #39421924
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
В общем мне надо кривой костыль, который будет быстро и надежно работать внутри либы. А снаружи все будет чопорно и по фэншую.
...
Рейтинг: 0 / 0
Как вызвать деструктор не зная тип объекта?
    #39421976
Siemargl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T,

>еще лишний тормоз в виде вызова виртуальных методов.

Это одна ассемблерная инструкция. Это не тормоз
...
Рейтинг: 0 / 0
Как вызвать деструктор не зная тип объекта?
    #39421991
Фотография SashaMercury
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ДмитрийСделать полноценные типизированные сообщения вообще не вариант: один обработчик может получать несколько типов сообщений. Для либы без разницы какие типы, главное доставить их в порядке отправления, т.е. очередь из разных типов. Можно конечно классическое наследование, т.е. базовый класс my_msg_t и гонять указатель на него, но я тут теряю простоту написания кода, я не смогу сделать сообщение из std::string или std::vector, я буду вынужден объявить класс производный от my_msg_t где внутри будет std::string. Кроме лишних букав в коде это еще лишний тормоз в виде вызова виртуальных методов.

Мне кажется, что нужно создать базовый класс-обертку, который и будет содержать всю необходимую информацию. И виртуальные функции здесь пригодятся. Собственно то, что ты и написал выше. Только ты почему-то рассуждаешь в таком формате, словно это будет избыточным, но по-моему это так не выглядит))
...
Рейтинг: 0 / 0
Как вызвать деструктор не зная тип объекта?
    #39421992
Фотография SashaMercury
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
BarloneDima TМожет как-то можно извернуться на шаблонах и адрес деструктора изначально сохранить при создании сообщения в create<T>(), а в erase() просто его вызвать?
Можно конечно. Сделайте вместо шаблонных функций шаблонный класс со статическими методами, и в нем же функцию очистки, вызывающую деструктор.


Как же это правильно называется, это уже давно планируют добавить в стандарт..
...
Рейтинг: 0 / 0
Как вызвать деструктор не зная тип объекта?
    #39422005
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T
Может еще какие-то способы есть?

в таких случаях самое правильное -вызвать деструктор руками.
...
Рейтинг: 0 / 0
Как вызвать деструктор не зная тип объекта?
    #39422042
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сделал костыль. Так работает.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
typedef void(*destructor_t)(void* obj);

// Сообщение
struct msg_t {
	destructor_t free;
	char data[];
};

// Обертка вызова деструктора
template <typename T>
void free_obj(void* obj) {
	T* ptr = (T*)obj;
	ptr->~T();
}

// Создание сообщения
template <typename T>
msg_t* create() {
	msg_t* msg = (msg_t*)malloc(sizeof(msg_t) + sizeof(T));
	msg->free = free_obj<T>; // Деструктор
	void* ptr = msg->data;
	new (ptr) T(); // Вызов конструктора содержимого
	return msg;
}

// Освобождение памяти
void erase(msg_t* msg) {
	msg->free(msg->data); // Вызов деструктора содержимого
	free(msg);
}
...
Рейтинг: 0 / 0
Как вызвать деструктор не зная тип объекта?
    #39422053
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SashaMercuryМне кажется, что нужно создать базовый класс-обертку, который и будет содержать всю необходимую информацию. И виртуальные функции здесь пригодятся. Собственно то, что ты и написал выше. Только ты почему-то рассуждаешь в таком формате, словно это будет избыточным, но по-моему это так не выглядит))
Я к С привык, в С++ слабо разбираюсь, но кое-что оттуда надо, например STD. Наверно поэтому :)

Прикинул, букав действительно не намного больше. Можно затестить с оберткой, тем более там виртуальных функций особо не надо вызывать, их там нет, msg_t это структура.

Тогда возникает следующий вопрос: если я перегружу new для базового класса (msg_t), то будет ли он вызываться при создании объекта дочернего класса? Я хочу простенький менеджер памяти добавить, т.е. не освобождать память сразу, а откладывать указатель в кэш и при следующем создании сообщения такого же размера просто выдавать из кэша.
...
Рейтинг: 0 / 0
Как вызвать деструктор не зная тип объекта?
    #39422137
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TМожно затестить с оберткой, тем более там виртуальных функций особо не надо вызывать, их там нет, msg_t это структура.
msg->free - это и есть виртуальная функция ))

Код: plaintext
1.
2.
3.
4.
5.
6.
// Обертка вызова деструктора
template <typename T>
void free_obj(void* obj) {
	T* ptr = (T*)obj;
	ptr->~T();
}


Так и надо делать. Это называется type erasure.
То же самое делают всякие std::function, std::shared_ptr

Dima TТогда возникает следующий вопрос: если я перегружу new для базового класса (msg_t), то будет ли он вызываться при создании объекта дочернего класса? Я хочу простенький менеджер памяти добавить, т.е. не освобождать память сразу, а откладывать указатель в кэш и при следующем создании сообщения такого же размера просто выдавать из кэша.
Не помнимаю, зачем спрашивать на форуме то что можно прочесть в доке или самому проверить несколькими строками кода?
Это настолько редкая в использовании фича, что вряд ли кто-то помнит подробности.
...
Рейтинг: 0 / 0
Как вызвать деструктор не зная тип объекта?
    #39422179
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Anatoly MoskovskyТак и надо делать. Это называется type erasure.
Ок. Так и сделаю.

Anatoly MoskovskyНе помнимаю, зачем спрашивать на форуме то что можно прочесть в доке или самому проверить несколькими строками кода?
Это настолько редкая в использовании фича, что вряд ли кто-то помнит подробности.
Мысли вслух. Вдруг кто помнит или какие-то подводные камни есть. Уже не важно, остаюсь на своем варианте.
...
Рейтинг: 0 / 0
Как вызвать деструктор не зная тип объекта?
    #39422769
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima T
Код: plaintext
1.
void* msg = malloc(sizeof(size_t) + sizeof(T));

если уж хочется такого хардкора, то почему бы в msg не завести поле, которое будет хранить тип T? И потом в зависимости от него вызывать правильный деструктор (по сути, те же виртуальные функции)
Во-вторых, а нужен ли деструктор для T? Или достаточно освободить память из-под объекта?
В-третьих, присоединяюсь к идее про шаблонный класс.
В-четвёртых, можно использовать те же "механизмы", которые используются в windows messaging
А можно ещё такой финт сделать: при создании делать make_shared<T> а указатель хранить в поле msg, после удаления которой автоматически будет вызван деструтор T. Но тут надо подумать, потому как похоже на выстрел в ногу.
...
Рейтинг: 0 / 0
Как вызвать деструктор не зная тип объекта?
    #39422773
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CEMbDima T
Код: plaintext
1.
void* msg = malloc(sizeof(size_t) + sizeof(T));

если уж хочется такого хардкора, то почему бы в msg не завести поле, которое будет хранить тип T? И потом в зависимости от него вызывать правильный деструктор (по сути, те же виртуальные функции)
Во-вторых, а нужен ли деструктор для T? Или достаточно освободить память из-под объекта?
В-третьих, присоединяюсь к идее про шаблонный класс.
В-четвёртых, можно использовать те же "механизмы", которые используются в windows messaging
А можно ещё такой финт сделать: при создании делать make_shared<T> а указатель хранить в поле msg, после удаления которой автоматически будет вызван деструтор T. Но тут надо подумать, потому как похоже на выстрел в ногу.
В реальном коде такого хардкора нет, есть msg_t переменной длины, упрощенно тут 20308304
msg_t нельзя делать шаблонным классом, т.к. например msg_t<int> и msg_t<std::string> надо ставить в одну очередь
Без деструкторов уже все работает и с освобождением памяти под сообщением проблемы порешаны.
Деструкторы нужны чтобы освобождать память которую T дополнительно в куче выделит, в первую очередь это касается объектов STD.
...
Рейтинг: 0 / 0
Как вызвать деструктор не зная тип объекта?
    #39422909
Фотография CEMb
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima Tmsg_t нельзя делать шаблонным классом, т.к. например msg_t<int> и msg_t<std::string> надо ставить в одну очередьшаблон можно специализировать в зависимости от того, класс ли T: std::is_class<T>, а в одну очередь можно поставить или через наследование от интерфейса или примерно так: 20172805 и 20256178 , там как раз идея скорости и отсутствия виртуальных функций в классах.
...
Рейтинг: 0 / 0
Как вызвать деструктор не зная тип объекта?
    #39422912
YesSql
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Dima Tпропущено...
msg_t нельзя делать шаблонным классом, т.к. например msg_t<int> и msg_t<std::string> надо ставить в одну очередь
Без деструкторов уже все работает и с освобождением памяти под сообщением проблемы порешаны.
Деструкторы нужны чтобы освобождать память которую T дополнительно в куче выделит, в первую очередь это касается объектов STD.
как то так
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
struct msg_base_t
{
       size_t     size;
       size_t     hash_type;
      //    .....etc.....

      msg_base_t(size_t _size, size_t _hash_type)
      : size      {_size}
      , hash_type {_hash_type}
      {}

      virtual ~msg_base_t();
};

template <typename M>
struct msg_t : public msg_base_t
{
       M  payload;

       msg_t(const M &m)
       : msg_base_t(sizeof(M), typeid(M).hash_code())
       , payload(m)
       {}

};

template <typename M>
void push(const M &m)
{ 
       msg_base_t *ptr = new  msg_t<M>(m);
}


Можно ещё попробовать вариадик и/или мув симантику. Может сэкономить на конструкторах.
.
...
Рейтинг: 0 / 0
Как вызвать деструктор не зная тип объекта?
    #39423486
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
YesSql, долго пытался понять что я выигрываю по сравнению со своим вариантом 20308304

Все что вижу - это строчка на создании сообщения
Код: plaintext
1.
2.
3.
my_msg_t msg;
... заполняем msg
push(msg);


и у меня
Код: plaintext
1.
2.
3.
4.
msg_t* msg = create<my_msg_t>();
my_msg_t* obj = get<my_msg_t>();
... заполняем obj
push(msg);


Твой вариант получше, но это все плюсы. Дальше все точно также: при получении будет msg_t* и приведение его к исходному типу. Дальше отправка того же msg_t*.

В твоем варианте мне надо курить перемещения (которые я не знаю), чтобы избавиться от копирования. Потом изучать перегрузку new/delete. Это минимум неделя изучения С++, а то и больше, я дотошный. Жалко мне неделю на это тратить.
...
Рейтинг: 0 / 0
Как вызвать деструктор не зная тип объекта?
    #39423550
YesSql
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Dima TYesSql, долго пытался понять что я выигрываю по сравнению со своим вариантом 20308304


Хочешь вызвать корректный деструктор неизвестного сообщения?
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
struct MyMessage
{
     std::string param1;
     int param2;
   
     MyMessage(const std::string _param1, int _param2)
      : param1    {_param1}
      , param2    {_param2}
     {}
};
   
         void * current_queue_ptr = malloc(sizeof(msg_t<MyMessage>));

         new(current_queue_ptr)  msg_t<MyMessage>(MyMessage("text param 1", 42));

//.................

         static_cast<msg_base_t *>(current_queue_ptr)->~msg_base_t();
...
Рейтинг: 0 / 0
Как вызвать деструктор не зная тип объекта?
    #39423555
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
YesSqlХочешь вызвать корректный деструктор неизвестного сообщения?

Я его и вызову 20308304 , msg->free это указатель на функцию, которая вызовет деструктор именно для того типа, который передан в конструктор. Как выше написали это стандартный велосипед вызова деструктора.
...
Рейтинг: 0 / 0
Как вызвать деструктор не зная тип объекта?
    #39423564
д0kХ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
YesSql
Код: plaintext
1.
         static_cast<msg_base_t *>(current_queue_ptr)->~msg_base_t();



ИМХО нельзя так делать ->~
Это пистолет в кармане со снятым предохранителейм ,
прострел ноги вопрос времени , он рано или поздно произойдет
в самый неожиданный момент.
...
Рейтинг: 0 / 0
Как вызвать деструктор не зная тип объекта?
    #39423607
YesSql
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
д0kХYesSql
Код: plaintext
1.
         static_cast<msg_base_t *>(current_queue_ptr)->~msg_base_t();



ИМХО нельзя так делать ->~
Это пистолет в кармане со снятым предохранителейм ,
прострел ноги вопрос времени , он рано или поздно произойдет
в самый неожиданный момент.
Это C++ карл, сдесь каждый угол заминирован.
...
Рейтинг: 0 / 0
Как вызвать деструктор не зная тип объекта?
    #39423612
YesSql
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Dima TYesSqlХочешь вызвать корректный деструктор неизвестного сообщения?

Я его и вызову 20308304 , msg->free это указатель на функцию, которая вызовет деструктор именно для того типа, который передан в конструктор. Как выше написали это стандартный велосипед вызова деструктора.
то же самое только без костыля.
...
Рейтинг: 0 / 0
Как вызвать деструктор не зная тип объекта?
    #39423771
ermak.nn
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Люблю я и C, и кресты, но как-то вместе они выглядят жутковато :)

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
class Message
{
public:
    Message();
    virtual ~Message();
    virtual void process() = 0;
};

template <class T>
class MessageTemplate : public Message
{
private:
    T* m_obj;
    
public:
    MessageTemplate();
    ~MessageTemplate();
    void process() override
    {
        // process message
    }
};



Я бы, наверно, сделал как-то так, но вы говорите, что элегантность теряется. Может быть, спорить не буду. Кишки библиотеки просто выглядят, хм... странно для человека, который пишет C++.
...
Рейтинг: 0 / 0
Как вызвать деструктор не зная тип объекта?
    #39423799
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ermak.nnКишки библиотеки просто выглядят, хм... странно для человека, который пишет C++.
Сначала я хотел ограничится только С с классами, т.е. было
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
class lite_msg_t {
	size_t _type;		// Тип сообщения
	size_t _size;		// Размер data, байт
public:
	char data[];		// Данные

	static lite_msg_t* create(size_t size, size_t type = 0) noexcept {
		lite_msg_t* msg = (lite_msg_t*)malloc(size + sizeof(lite_msg_t));
...


Красиво и по Сишному. Оно так и осталось.
Все что касается типов вложений хотел чтобы осталось поверх этого. Но как-то не очень код выглядит с постоянными <my_msg_t>
Пока нет времени этим заниматься, подумаю, может вообще выкину все шаблоны и оставлю только явное наследование. Тесты показали что на скорость это никак не влияет.
...
Рейтинг: 0 / 0
25 сообщений из 25, страница 1 из 1
Форумы / C++ [игнор отключен] [закрыт для гостей] / Как вызвать деструктор не зная тип объекта?
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]