shared_from_this() 即使正确使用 make_shared 也会导致 std::bad_weak_ptr
shared_from_this() causes std::bad_weak_ptr even when correctly using make_shared
我正在使用独立的 Asio 和 C++11 创建 C++ 服务器应用程序,但出现错误,这就是我寻求帮助的原因。
错误
在classworker_thread
中,调用shared_from_this()
时,抛出bad_weak_ptr
异常,导致程序崩溃。
布局
- class
connection_manager
在 std::vector
容器 中创建并存储 std::shared_ptr<worker_thread>
类型的对象
- class
worker_thread
继承自 std::enable_shared_from_this<worker_thread>
.
- class
worker_thread
创建类型为 std::shared_ptr<connection>
的对象。
- class
connection
需要一个指向 class worker_thread
的指针(这是一个共享指针),以便可以调用 void handle_finish(std::shared_ptr<connection>)
程序流程
- class
worker_thread
是通过其构造函数创建的,从 class connection_manager
使用 std::make_shared<worker_thread>
和两个共享指针作为参数。
void init()
由 connection_manager
从 worker_thread
调用
- 稍后在程序中,
connection_manager
从 worker_thread
调用 std::shared_ptr<connection> get_available_connection()
- 在此方法执行期间,通过
std::make_shared<connection>
创建了一个新的 connection
,其中一个参数是指向 current worker_thread
通过 shared_from_this()
获得
- 在
shared_from_this()
调用期间,程序崩溃并出现 bad_weak_ptr
异常。
研究
根据我的研究,导致此错误的最常见原因是:
- 当
shared_from_this()
在构造函数(或构造函数调用的函数)中调用时
- 当不存在
std::shared_ptr
指向对象时。
在我的程序中:
- 对构造函数的调用和
get_available_connection()
是分开的,通过终端中的输出行,似乎 worker_thread
是在调用 [=48 时构造和初始化的=]发生
connection_manager
class 持有指向每个 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;
}
}
如果这个问题之前有人回答过,我很抱歉,但我试图解决这个问题,在尝试了一段时间后,我决定寻求帮助会更好。
编辑
这是一个最低限度的测试,它失败了。它需要 CMake,并且您可能必须更改所需的最低版本。
我认为你的问题可能是你使用了默认的 private
继承。
这是一个程序崩溃的简单示例:
class GoodUsage : public std::enable_shared_from_this<GoodUsage>
{
public:
void DoSomething()
{
auto good = shared_from_this();
}
};
class BadUsage : std::enable_shared_from_this<BadUsage> // private inheritance
{
public:
void DoSomething()
{
auto bad = shared_from_this();
}
};
int main()
{
auto good = std::make_shared<GoodUsage>();
auto bad = std::make_shared<BadUsage>();
good->DoSomething(); // ok
bad->DoSomething(); // throws std::bad_weak_ptr
}
我正在使用独立的 Asio 和 C++11 创建 C++ 服务器应用程序,但出现错误,这就是我寻求帮助的原因。
错误
在classworker_thread
中,调用shared_from_this()
时,抛出bad_weak_ptr
异常,导致程序崩溃。
布局
- class
connection_manager
在std::vector
容器 中创建并存储 - class
worker_thread
继承自std::enable_shared_from_this<worker_thread>
. - class
worker_thread
创建类型为std::shared_ptr<connection>
的对象。 - class
connection
需要一个指向 classworker_thread
的指针(这是一个共享指针),以便可以调用void handle_finish(std::shared_ptr<connection>)
std::shared_ptr<worker_thread>
类型的对象
程序流程
- class
worker_thread
是通过其构造函数创建的,从 classconnection_manager
使用std::make_shared<worker_thread>
和两个共享指针作为参数。 void init()
由connection_manager
从 - 稍后在程序中,
connection_manager
从worker_thread
调用 - 在此方法执行期间,通过
std::make_shared<connection>
创建了一个新的connection
,其中一个参数是指向 currentworker_thread
通过shared_from_this()
获得
- 在
shared_from_this()
调用期间,程序崩溃并出现bad_weak_ptr
异常。
worker_thread
调用
std::shared_ptr<connection> get_available_connection()
研究
根据我的研究,导致此错误的最常见原因是:
- 当
shared_from_this()
在构造函数(或构造函数调用的函数)中调用时 - 当不存在
std::shared_ptr
指向对象时。
在我的程序中:
- 对构造函数的调用和
get_available_connection()
是分开的,通过终端中的输出行,似乎worker_thread
是在调用 [=48 时构造和初始化的=]发生 connection_manager
class 持有指向每个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;
}
}
如果这个问题之前有人回答过,我很抱歉,但我试图解决这个问题,在尝试了一段时间后,我决定寻求帮助会更好。
编辑 这是一个最低限度的测试,它失败了。它需要 CMake,并且您可能必须更改所需的最低版本。
我认为你的问题可能是你使用了默认的 private
继承。
这是一个程序崩溃的简单示例:
class GoodUsage : public std::enable_shared_from_this<GoodUsage>
{
public:
void DoSomething()
{
auto good = shared_from_this();
}
};
class BadUsage : std::enable_shared_from_this<BadUsage> // private inheritance
{
public:
void DoSomething()
{
auto bad = shared_from_this();
}
};
int main()
{
auto good = std::make_shared<GoodUsage>();
auto bad = std::make_shared<BadUsage>();
good->DoSomething(); // ok
bad->DoSomething(); // throws std::bad_weak_ptr
}