Используется следующая модель абстракции:
//SHP_*** обозначены shared_ptr<***>
class A
{
std::vector<SHP_B> vecB;
boost::asio::io_service io;
}
class B
{
B(...){socket = std::make_shared<Socket>(...);}
~B(){socket->s.close();}
private: SHP_Socket socket;
}
class Socket
{
Socket(...){s.open(...); s.set_option(...); s.bind(...);}
boost::asio::ip::udp::socket s;
}
Все эти классы и их реализация лежат в разных файлах.
Все прекрасно собирается, работает, инициализируется, сокеты шлют данные. В vecB добавляются и удаляются элементы... Пока не вызову деструктор класса А. При этом, в vecB должно содержаться (и содержится, проверил) 2 элемента SHP_B.
Тогда возникает ошибка доступа к памяти: Unhandled exception at 0x77BE57DA (ntdll.dll) in Conference.exe: 0xC0000005: Access violation reading location 0xFEEEFEF6. и дебагер кидает в файл: ...\boost\asio\detail\impl\win_iocp_socket_service_base.ipp
void win_iocp_socket_service_base::destroy(
win_iocp_socket_service_base::base_implementation_type& impl)
{
close_for_destruction(impl);
// Remove implementation from linked list of all implementations.
boost::asio::detail::mutex::scoped_lock lock(mutex_);
if (impl_list_ == &impl) // <- дебагер указывает на эту строчку
impl_list_ = impl.next_;
if (impl.prev_)
impl.prev_->next_ = impl.next_;
if (impl.next_)
impl.next_->prev_= impl.prev_;
impl.next_ = 0;
impl.prev_ = 0;
}
Я так понимаю, что ошибка вызвана попыткой удаления уже удаленного сокета или попыткой удаления открытого сокета(что вряд ли), но почему? Закрытие сокета я вызываю только в ~B(), который после исполнения должен вызвать и деструктор класса Socket, в котором вызывается деструктор для boost::asio::ip::udp::socket s., пробовал закрывать вызовом вручную и удаление элементов из vecB по одному перед вызовом деструктора по умолчанию для класса А (ведь до того как мне надо удалить объект из A нормально работало...). Пробовал перенести закрытие сокета в ~Socket() - не помогло.
Из-за чего возникла эта проблема и как ее решить?
Как выяснилось в комментариях проблема в том, что объект типа boost::asio::io_service уничтожается раньше чем последний созданный на нем сокет.
Чтобы избежать этой ситуации можно создать пользовательский деструктор с правильным порядком очистки, что Вы и сделали. А можно просто поменять порядок членов:
class A
{
boost::asio::io_service io;
std::vector<SHP_B> vecB;
};
В таком случае, автоматически созданный деструктор будет сначала удалять vecB, а потом уже io. Правда в этом случае надо иметь в виду, что т.к. используется shared_ptr сокет может формально существовать ещё где-то. Если его существование в другим местах не предполагается - имеет смысл использовать другой тип умного указателя, например unique_ptr.
Проблема в том, что ваш io_service уничтожается раньше, чем уничтожается сокет. Продлить время жизни можно двумя способами:
Вынести io_service наружу. Хорошим местом для создания io_service будет локальная переменная в функции main или в какой-нибудь подобной. Или вообще глобальная/статическая.
Создавать io_service через shared_ptr, сохраняя копию в каждом классе B.
Как развивать веб-проекты в 2026 году: технологии, контент E-E-A-T и факторы доверия
Современные инструменты для криптотрейдинга: как технологии помогают принимать решения
Апостиль в Лос-Анджелесе без лишних нервов и бумажной волокиты
Основные этапы разработки сайта для стоматологической клиники