четверг, 20 июля 2023 г.

[prog.c++.wtf] Голый владеющий указатель на shared_ptr?

Чего только в жизни не бывает! Похоже, что я оказываюсь в ситуации, когда потребуется поиметь голый владеющий указатель на std::shared_ptr. Что-то вроде (псевдокод для иллюстрации, не претендует на production readyness):

void ready_handler(const mg_connection * conn, void *) {
   auto shared_conn_data = std::make_shared<connection_data_t>(...);
   auto * owning_ptr = new std::shared_ptr<connection_data_t>{shared_conn_data};

   mg_set_user_connection_data(conn, owning_ptr); // Только за этим onwing_ptr и нужен был.
                                                  // Нельзя таким образом сохранить весь shared_ptr.

   send_to_external_thread(shared_conn_data);
}
...
void close_handler(const mg_connection * conn, void *) {
   auto * owning_ptr = reinterpret_cast<std::shared_ptr<connection_data_t>>(
         mg_get_user_connection_data(conn));
   // Этот экземпляр больше не нужен.
   // Если где-то на внешней нити остался свой shared_ptr, то connection_data_t продолжит
   // свое существование и после выхода из close_handler.
   // Если нет, то connection_data_t умрет прямо сейчас.
   delete owning_ptr;
}

Интеграция с написанным на чистом Си коде. Ничего лучшего пока не придумывается :)

4 комментария:

night beast комментирует...

intrusive_ptr + IRefCounted ?

eao197 комментирует...

@night beast

Да, первая мысль была именно об этом. Но в проекте нет готового intrusive_ptr (и Boost-а нет). Подключать что-то ради одного места в коде... Хотя можно, конечно, заглянуть в потроха SObjectizer-а и поиспользовать функциональность оттуда. Но...

Но все равно в месте вызова mg_set_user_connection_data и msg_get_user_connection_data будет присутствовать голый указатель, с которым еще и специальным образом работать нужно (т.е. вызывать функции инкремента/декремента счетчика вручную).

Так что, имхо, голый владеющий указатель тут даже очевиднее и проще как-то.

sv комментирует...

Мне кажется, для похожей задачи я использовал std::list. И в самом объекте итератор на самого себя в этом листе. И когда объект больше не нужен, удаляем самого себя из std::list-а. Единственный случай, когда пригодился list :)

night beast комментирует...

@eao197

для msg_set_user_connection_data/msg_get_user_connection_data можно написать обертки, которые наружу будут отдавать уже типизированные данные

голый указатель на умный указатель выглядит дико )