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

C++中如何通过引用传递指针且不破坏shared_ptr的共享机制?

解决C++智能指针与外部裸指针的生命周期匹配问题

首先得明确你原代码的核心问题:函数里的shared_ptr是局部变量,当函数执行完毕时,这些局部智能指针会被销毁,它们持有的对象引用计数降到0,对象也就被自动释放了——这就导致你外部拿到的裸指针直接悬空,后续访问肯定会触发未定义行为。

要实现“外部用裸指针,不用管内存管理”的需求,本质上是要让对象的生命周期覆盖外部裸指针的使用周期,同时让智能指针自动管理内存。下面给你几个可行的方案,按推荐程度排序:

方案1:自定义RAII包装类(最贴合你的理想调用方式)

写一个轻量的包装类,内部用shared_ptr持有对象,同时提供裸指针的隐式转换和指针操作符重载,这样外部使用起来和裸指针几乎完全一样,内存管理全交给内部的智能指针。

#include <memory>

template<typename T>
class AutoRawPtr {
private:
    std::shared_ptr<T> internal_ptr_;

public:
    // 默认构造
    AutoRawPtr() = default;
    // 用shared_ptr初始化
    explicit AutoRawPtr(std::shared_ptr<T> ptr) : internal_ptr_(std::move(ptr)) {}

    // 隐式转换为裸指针,直接用就行
    operator T*() const {
        return internal_ptr_.get();
    }

    // 重载指针操作符,支持->和*
    T& operator*() const {
        return *internal_ptr_;
    }

    T* operator->() const {
        return internal_ptr_.get();
    }

    // 可选:判断指针是否有效
    bool is_valid() const {
        return static_cast<bool>(internal_ptr_);
    }
};

// 你的函数改成这样
void do_something(AutoRawPtr<whatever>& A, AutoRawPtr<whatever>& B) {
    A = AutoRawPtr<whatever>(std::make_shared<whatever>());
    B = AutoRawPtr<whatever>(std::make_shared<whatever>());
}

// 调用方式完全符合你的理想
AutoRawPtr<whatever> A, B;
do_something(A, B);
// 直接用A、B,和裸指针一模一样
A->do_something();
whatever* raw = A;
// 不用管释放,AutoRawPtr销毁时自动释放对象

这个方案的优点:

  • 外部调用几乎和裸指针完全一致,不需要手动管理内存
  • 完全遵循RAII原则,对象生命周期和AutoRawPtr绑定,不会出现悬空
  • 支持自定义删除器(只要在make_shared或者构造shared_ptr时指定就行)

方案2:让函数接收shared_ptr引用(C++最佳实践)

虽然稍微改变了你的调用方式,但这是最符合C++标准和安全规范的做法。外部声明shared_ptr,函数内部完成初始化,外部可以用get()拿到裸指针来使用,内存完全由shared_ptr自动管理。

#include <memory>

void do_something(std::shared_ptr<whatever>& A, std::shared_ptr<whatever>& B) {
    A = std::make_shared<whatever>();
    B = std::make_shared<whatever>();
}

// 调用方式
std::shared_ptr<whatever> A, B;
do_something(A, B);
// 拿到裸指针使用
whatever* a_raw = A.get();
whatever* b_raw = B.get();

// 业务逻辑...
// 不用管释放,A、B销毁时自动释放对象

这个方案的优点:

  • 完全使用标准库组件,不需要自己写包装类
  • 安全性极高,不会出现悬空指针(只要你不手动释放get()拿到的裸指针)
  • 支持所有shared_ptr的特性,比如自定义删除器、多线程安全的引用计数

方案3:全局/静态智能指针容器(不推荐,仅作参考)

把创建的shared_ptr存储到一个全局或者静态的容器里,让容器的生命周期覆盖外部裸指针的使用周期。但这个方案有明显的缺点:内存不会及时释放,直到容器被清理或者程序结束,容易造成内存浪费。

#include <memory>
#include <vector>

// 全局容器,存储所有创建的shared_ptr
template<typename T>
struct PtrHolder {
    static std::vector<std::shared_ptr<T>> holders;
};

template<typename T>
std::vector<std::shared_ptr<T>> PtrHolder<T>::holders;

void do_something(whatever*& A, whatever*& B) {
    auto a_ptr = std::make_shared<whatever>();
    A = a_ptr.get();
    PtrHolder<whatever>::holders.push_back(std::move(a_ptr));

    auto b_ptr = std::make_shared<whatever>();
    B = b_ptr.get();
    PtrHolder<whatever>::holders.push_back(std::move(b_ptr));
}

// 调用方式和你原来的一样
whatever* A, *B;
do_something(A, B);
// 使用A、B...
// 注意:对象会一直存在到程序结束,除非手动清理PtrHolder::holders

这个方案只适合短期测试或者非常特殊的场景,不推荐在生产代码中使用。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 07:33:13