Я создаю серверное приложение C ++ с использованием автономных Asio и C ++ 11 и получаю сообщение об ошибке, поэтому прошу помощи.
Ошибка
В классе worker_thread
во время вызова shared_from_this()
возникает исключение bad_weak_ptr
, которое вызывает сбой программы.
Макет
- Класс
connection_manager
создает и хранит объекты типа std::shared_ptr<worker_thread>
внутри std::vector
контейнера
- Класс
worker_thread
наследуется от std::enable_shared_from_this<worker_thread>
.
- Класс
worker_thread
создает объекты типа std::shared_ptr<connection>
.
- Класс
connection
требует указатель (который является общим указателем) на класс worker_thread
, чтобы он мог вызывать void handle_finish(std::shared_ptr<connection>)
Программный поток
- Класс
worker_thread
создается через его конструктор, из класса connection_manager
, используя std::make_shared<worker_thread>
с двумя общими указателями в качестве параметров.
void init()
вызывается с worker_thread
по connection_manager
- Позже в программе
connection_manager
звонит std::shared_ptr<connection> get_available_connection()
с worker_thread
- Во время выполнения этого метода новый
connection
создается с помощью std::make_shared<connection>
, и одним из аргументов является общий указатель на current worker_thread
, полученный с помощью shared_from_this()
- Во время вызова
shared_from_this()
программа вылетает с исключением bad_weak_ptr
.
Исследования
Из моего исследования, наиболее распространенные причины этой ошибки:
- Когда
shared_from_this()
вызывается внутри конструктора (или функции, которая вызывается конструктором)
- Когда не существует
std::shared_ptr
, указывающего на объект.
В моей программе:
- Вызов конструктору и
get_available_connection()
являются отдельными, и через вывод строк в терминале создается впечатление, что worker_thread
создается и инициализируется к тому времени, когда происходит вызов get_available_connection()
- Класс
connection_manager
содержит общий указатель на каждый worker_thread
объект.
Код
Все something_ptr
являются std::shared_ptr<something>
Заголовочные файлы
connection_manager.hpp
typedef asio::executor_work_guard<asio::io_context::executor_type>
io_context_work;
std::vector<worker_thread_ptr> workers;
std::vector<io_context_ptr> io_contexts;
std::vector<io_context_work> work;
worker_thread.hpp
class worker_thread : std::enable_shared_from_this<worker_thread> {
public:
/// Create a worker thread.
explicit worker_thread(io_context_ptr io, config_ptr vars_global);
void init();
void join();
connection_ptr get_available_connection();
//...
connection.hpp
explicit connection(std::shared_ptr<worker_thread> worker,
std::shared_ptr<asio::io_context> io,
config_ptr vars_parent);
Исходные файлы
connection_manager.cpp
connection_manager::connection_manager(config_ptr vars) {
std::size_t number_of_threads = vars->worker_threads;
while(number_of_threads > 0) {
io_context_ptr io_context(new asio::io_context);
io_contexts.push_back(io_context);
work.push_back(asio::make_work_guard(*io_context));
worker_thread_ptr worker =
std::make_shared<worker_thread>(io_context, vars);
workers.push_back(worker);
worker->init();
--number_of_threads;
}
}
connection_ptr connection_manager::get_available_connection() {
std::size_t index_of_min_thread = 0;
std::size_t worker_count = workers.size();
for(std::size_t i = 1; i < worker_count; ++i) {
if(workers[i]->active_connection_count() <
workers[index_of_min_thread]->active_connection_count())
index_of_min_thread = i;
}
return workers[index_of_min_thread]->get_available_connection();
}
worker_thread.cpp
worker_thread::worker_thread(io_context_ptr io,
config_ptr vars_global)
:io_context(io), active_conn_count(0), vars(vars_global),
worker(
[this]() {
if(io_context)
io_context->run();
}
) {}
void worker_thread::init() {
//Additional initialisation, this is called by connection_manager
//after this thread's construction
}
connection_ptr worker_thread::get_available_connection() {
connection_ptr conn;
if(!available_connections.empty()) {
conn = available_connections.front();
available_connections.pop();
active_connections.insert(conn);
return conn;
} else {
conn = std::make_shared<connection>(shared_from_this(), io_context, vars);
active_connections.insert(conn);
return conn;
}
}
Прошу прощения, если на этот вопрос уже был дан ответ, но я попытался решить эту проблему, и, попробовав какое-то время, я решил, что лучше обратиться за помощью.
EDIT
Вот минимальный тест, который не проходит. Требуется CMake, и вам, возможно, придется изменить минимально требуемую версию .
Ссылка на Google Диск