三种智能指针不用和用的写法

一、场景:手动管理 vs 智能指针管理

方式特点内存管理
❌ 普通指针需要手动 new / delete容易泄漏或悬空
✅ 智能指针自动释放安全、简洁

二、unique_ptr(独占所有权)

基本用法对比

不用智能指针

Foo* p = new Foo();
// 使用
p->doSomething();
// 手动释放
delete p;

unique_ptr

#include <memory>

auto p = std::make_unique<Foo>(); // 推荐写法(C++14+)
// 使用
p->doSomething();  
// 离开作用域自动 delete,无需手动释放

函数传参

void func(std::unique_ptr<Foo> p); // 独占所有权传入(会转移)
func(std::move(p));  // 调用后p变空

函数返回

std::unique_ptr<Foo> createFoo() {
    return std::make_unique<Foo>();  // 自动返回(移动语义)
}

适用场景:对象只会被一个地方使用;生命周期明确。


三、shared_ptr(共享所有权)

 基本用法对比

不用智能指针

Foo* p1 = new Foo();
Foo* p2 = p1; // 指向同一对象
delete p1;    // ❌ p2 变悬空指针

shared_ptr

#include <memory>

auto p1 = std::make_shared<Foo>();
auto p2 = p1;  // 引用计数 +1

p1->doSomething();
p2->doSomething();

// 作用域结束时,最后一个shared_ptr销毁对象

函数传参

void func(std::shared_ptr<Foo> p) {
    p->doSomething();
}

auto obj = std::make_shared<Foo>();
func(obj); // 引用计数 +1,安全共享

函数返回

std::shared_ptr<Foo> createFoo() {
    return std::make_shared<Foo>();
}

auto p = createFoo(); // 调用者和返回者共享同一对象

适用场景:资源被多个模块共享使用,生命周期由引用计数控制。


四、weak_ptr(弱引用,不拥有对象)

 基本用法对比

不用智能指针(容易循环引用)

struct A;
struct B {
    A* pa;
};
struct A {
    B* pb;
};

手动管理极易出现重复释放内存泄漏


shared_ptr + weak_ptr

#include <memory>
#include <iostream>

struct A;
struct B;

struct A {
    std::shared_ptr<B> pb;
    ~A() { std::cout << "A析构\n"; }
};
struct B {
    std::weak_ptr<A> pa;  // 不增加引用计数
    ~B() { std::cout << "B析构\n"; }
};

int main() {
    auto a = std::make_shared<A>();
    auto b = std::make_shared<B>();
    a->pb = b;
    b->pa = a;
} // ✅ 自动析构,不会内存泄漏

检查对象是否还存在

std::shared_ptr<Foo> sp = std::make_shared<Foo>();
std::weak_ptr<Foo> wp = sp;

if (auto temp = wp.lock()) { // 安全访问
    temp->doSomething();
} else {
    std::cout << "对象已销毁\n";
}

适用场景

  • 避免循环引用(如父子节点、观察者模式)

  • 想“知道对象是否还活着”,但不想影响生命周期


五、综合示例(函数 + 变量 + 对象)

#include <iostream>
#include <memory>

struct Foo {
    Foo(int x) : val(x) { std::cout << "构造 " << val << "\n"; }
    ~Foo() { std::cout << "析构 " << val << "\n"; }
    void show() { std::cout << "值:" << val << "\n"; }
    int val;
};

// 使用 unique_ptr(独占)
void takeUnique(std::unique_ptr<Foo> p) {
    p->show();
}

// 使用 shared_ptr(共享)
void takeShared(std::shared_ptr<Foo> p) {
    std::cout << "use_count=" << p.use_count() << "\n";
    p->show();
}

int main() {
    // --- unique_ptr ---
    auto up = std::make_unique<Foo>(1);
    takeUnique(std::move(up)); // 所有权转移
    // up 已为空

    // --- shared_ptr ---
    auto sp1 = std::make_shared<Foo>(2);
    auto sp2 = sp1; // 引用计数+1
    takeShared(sp2); // 临时+1
    std::cout << "主函数计数=" << sp1.use_count() << "\n";

    // --- weak_ptr ---
    std::weak_ptr<Foo> wp = sp1;
    sp1.reset();  // 释放对象(计数变0,析构)
    if (wp.expired()) std::cout << "weak_ptr检测:对象已销毁\n";
}

六、总结口诀表

类型所有权能否复制能否共享是否自动释放常见用途
unique_ptr独占❌(只能移动)独占资源、局部对象
shared_ptr共享✅(计数归零时)资源共享
weak_ptr无(观察)防循环引用、检测有效性

记忆口诀:

  • 独占用 unique_ptr

  • 共用用 shared_ptr

  • 只看不用用 weak_ptr

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值