You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

被weak_ptr引用的unique_ptr能否移动?如何通过weak_ptr管理数据库连接?

关于用weak_ptr追踪unique_ptr并关闭数据库连接的问题解答

核心结论

  1. 不能用weak_ptr追踪unique_ptr:weak_ptr是为shared_ptr设计的,依赖shared_ptr的引用计数控制块追踪对象,而unique_ptr没有这个控制块,两者完全不兼容,没法通过weak_ptr追踪unique_ptr的状态。
  2. 不能直接把weak_ptr引用的内容move到unique_ptr:你写的unique_ptr<sql::Connection> conn_to_kill = std::move(weak_ptr_to_connection);代码无法编译——weak_ptr和unique_ptr是不同类型,且weak_ptr不拥有对象所有权,没有权限将对象从其他智能指针(哪怕是unique_ptr)处转移过来。

针对需求的解决方案

你的核心需求是:管理一批独占所有权的数据库连接(借出时转移所有权,归还时收回),收到终止信号时能关闭所有连接(包括正在被借出的)。这里有两种可行方案:

方案一:改用shared_ptr替代unique_ptr(推荐)

将连接的所有权从unique_ptr换成shared_ptr,这样就能用weak_ptr追踪所有连接,操作更简单:

  • 连接池用std::vector<std::shared_ptr<sql::Connection>>存储,借出时直接拷贝shared_ptr(无需move),归还时无需特殊操作(使用者用完后shared_ptr自动释放引用)。
  • 维护一个std::vector<std::weak_ptr<sql::Connection>>用于追踪所有连接,也可直接复用连接池容器(因为连接池始终保留每个连接的shared_ptr)。
  • 收到终止信号时,遍历weak_ptr容器,调用lock()获取有效的shared_ptr后关闭连接:
// 假设weak_conns是存储weak_ptr的容器
for (auto& weak_conn : weak_conns) {
    if (auto conn = weak_conn.lock()) {
        conn->close(); // 关闭数据库连接
        conn.reset(); // 可选:主动释放所有权
    }
}

注意:如果连接正在被其他线程使用,lock()会成功拿到shared_ptr,此时关闭连接可能导致正在执行的查询出错,需给每个连接配std::mutex,关闭前先上锁确保操作安全。

方案二:坚持用unique_ptr,手动追踪原始指针

如果必须用unique_ptr(比如数据库库要求独占连接),可以通过原始指针容器配合自定义删除器追踪:

  1. 维护一个线程安全的容器(比如带互斥锁的std::unordered_set<sql::Connection*>),存储所有连接的原始指针。
  2. 给unique_ptr设置自定义删除器,当连接被销毁时自动从追踪容器移除对应指针:
std::mutex conn_mutex;
std::unordered_set<sql::Connection*> all_conns;

// 自定义删除器
auto conn_deleter = [&](sql::Connection* conn) {
    std::lock_guard<std::mutex> lock(conn_mutex);
    all_conns.erase(conn);
    delete conn;
};

// 创建连接并加入追踪容器
auto conn = std::unique_ptr<sql::Connection, decltype(conn_deleter)>(create_sql_connection(), conn_deleter);
{
    std::lock_guard<std::mutex> lock(conn_mutex);
    all_conns.insert(conn.get());
}
  1. 借出连接时直接move unique_ptr即可(无需修改追踪容器,原始指针仍有效);归还时move回连接池。
  2. 收到终止信号时,遍历追踪容器关闭所有连接:
std::lock_guard<std::mutex> lock(conn_mutex);
for (auto conn : all_conns) {
    if (conn) {
        conn->close();
    }
}

这种方案需要自行处理线程安全和指针有效性,容易出现悬空指针问题,仅适合必须用unique_ptr的场景。

内容的提问来源于stack exchange,提问作者Sean

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 19:45:34