Используется следующая модель абстракции:
//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.
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Такой вопросЯ перегружаю операторы для работы с вектором, который состоит из трек точек