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

如何为std::unique_ptr实现类似weak_ptr的指针,避免双free问题

问题:如何在编译阶段阻止unique_ptr场景下手动delete导致的双free错误

给定以下存在错误的代码,运行后会产生无效输出并触发双free错误:

#include <memory>
#include <iostream>

class A
{
public:
    int i = 8;
};

class B {
public:
    std::unique_ptr<A> p;
};

int main()
{
    B b;
    b.p.reset(new A);
    std::cout << "Out1: " << b.p->i << std::endl;

    const A* const a = b.p.get();

    delete a; // 如何禁止这条语句?

    std::cout << "Out2: " << b.p->i << std::endl;
}

运行输出:

Out1: 8
Out2: 1587634531
free(): double free detected in tcache 2
Aborted

需求是:如何声明指针a,使其拥有对*a(A类型)的读写权限,但不会破坏unique_ptr对象B.p?const修饰指针并非解决方案。另外,std::shared_ptr有对应的std::weak_ptr,那么std::unique_ptr是否有类似机制?


解答

1. std::unique_ptr没有对应的弱引用机制

std::unique_ptr的核心设计是独占对象所有权,它不需要处理多所有权共享的场景,因此没有配套的weak_ptr类。

2. 编译阶段阻止手动delete的可行方案

要实现“能读写对象但无法手动delete”的目标,核心是让外部无法拿到可被delete的原始指针,或通过语法限制delete操作:

方案一:返回对象引用而非指针

直接获取A类型的引用,引用本身不支持delete操作,且能正常读写对象成员:

// 替换原代码中的const A* const a = b.p.get();
A& a = *b.p;

引用的语义天然是“借用”而非“拥有”,能明确传达意图,逻辑上可避免手动delete操作(语法上delete &a虽合法,但不符合引用使用规范,开发者不会这么写)。

方案二:封装类B的访问接口

在类B中提供获取对象的成员函数,返回引用而非原始指针,从根源上隐藏原始指针:

class B {
public:
    std::unique_ptr<A> p;
    // 提供可读写的引用
    A& getA() { return *p; }
    // 提供只读的const引用
    const A& getA() const { return *p; }
};

// main中使用
A& a = b.getA();

这样外部完全接触不到unique_ptr持有的原始指针,彻底杜绝手动delete的可能。

方案三:自定义非拥有指针类型(可选)

如果一定要用指针形式,可以封装一个简单的非拥有指针类,禁用转换为原始指针的操作,让delete无法编译:

template<typename T>
class non_owning_ptr {
public:
    explicit non_owning_ptr(T* ptr) : m_ptr(ptr) {}
    // 支持箭头和解引用操作,正常访问对象
    T* operator->() { return m_ptr; }
    T& operator*() { return *m_ptr; }
    // 禁止转换为可被delete的原始指针
    operator T*() = delete;
private:
    T* m_ptr;
};

// main中使用
non_owning_ptr<A> a(b.p.get());
// 此时尝试delete a会直接编译报错

为什么const修饰指针没用?

const A* const a只是限制了指针本身不能被修改,以及不能通过指针修改指向的对象,但指针依然是原始指针类型,编译器不会阻止对它执行delete操作,因此无法解决双free问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 11:27:33