C++ 智能指针详解及示例

C++ 智能指针是 C++11 引入的自动化内存管理工具,用于替代裸指针,防止内存泄漏和悬空指针问题。以下是三种主要智能指针的详细说明及示例:

1. std::unique_ptr:独占所有权

  • 特点

    1. 同一时间只能有一个 unique_ptr 指向对象。

    2. 对象生命周期与 unique_ptr 绑定,指针销毁时对象自动释放。

    3. 不可复制,但可通过 std::move 转移所有权。

  • 适用场景

    • 明确资源唯一所有权的场景(如工厂模式返回对象)。

  • 示例

#include <iostream>
#include <memory>

using namespace std;

class Resource {
public:
    Resource()
        {
                cout << "Resource Created" << endl;
        }

    ~Resource()
        {
                cout << "Resource Destroyed" << endl;
        }

    void use()
        {
                cout << "Using Resource " << endl;
        }
};

int main() {
    // 创建 unique_ptr
    unique_ptr<Resource> ptr1 = make_unique<Resource>();
    ptr1->use();  // 输出: Using Resource

    // 转移所有权
    unique_ptr<Resource> ptr2 = move(ptr1);
    if (!ptr1) {
        // 输出: ptr1 is now empty
        cout << "ptr1 is now empty" << endl; 
    }
    else{
        cout << "ptr1 is not empty" << endl;
    }
    // 测试指针ptr2
    if (ptr2){
        ptr2->use();
    }

    return 0;
}

编译以上程序并且测试结果如下:

(base) blctrl@blctrl-s2:~/CPP_Program$ ./sp
Resource Created
Using Resource
ptr1 is now empty
Using Resource
Resource Destroyed

2. std::shared_ptr:共享所有权

  • 特点

    1. 多个 shared_ptr 可共享同一对象。

    2. 通过引用计数跟踪对象使用者,计数归零时释放对象。

    3. 支持拷贝和赋值。

  • 适用场景

    • 多个组件需共享同一资源(如缓存系统、观察者模式)。

  • 示例

#include <iostream>
#include <memory>

using namespace std;

class Data {
public:
    Data()
    {
        m_data = 0;
        cout << "Data Created" << endl;;
    }

    Data(int data) : m_data(data)
    {
        cout << "Data Created: " << m_data << endl;;
    }

    ~Data()
    {
        cout << "Data Destroyed" << endl;;
    }
    
    void printData()
    {
        cout << "Data: " << m_data << endl;
    }
private:
    nt m_data;
};

int main() {
    // 创建 shared_ptr
    shared_ptr<Data> ptr1 = make_shared<Data>(10);  // 输出: Data Created:10
    {
        // 引用计数变为 2
        shared_ptr<Data> ptr2 = ptr1;  
        // 输出: 2
        cout << "Inside scope: Use count = " << ptr2.use_count() << "" << endl;;  
        ptr2->printData();
    }  // ptr2 销毁,引用计数变为 1

    cout << "Outside scope: Use count = " << ptr1.use_count() << "" << endl;;  // 输出: 1
    ptr1->printData();

    return 0;  // ptr1 销毁,引用计数归零,输出: Data Destroyed
}

编译以上程序,并且进行测试:

(base) blctrl@blctrl-s2:~/CPP_Program$ ./sp2
Data Created: 10
Inside scope: Use count = 2
Data: 10
Outside scope: Use count = 1
Data: 10
Data Destroyed

3. std::weak_ptr:弱引用

  • 特点

    1. 指向 shared_ptr 管理的对象,但不增加引用计数

    2. 需通过 lock() 方法获取临时 shared_ptr 访问对象。

    3. 用于解决 shared_ptr 的循环引用问题

  • 适用场景

    • 观察者模式、缓存系统中避免循环引用。

  • 示例(解决循环引用):

#include <iostream>
#include <memory>

using namespace std;

class NodeA; // 前向声明
class NodeB; // 前向声明

class NodeA {
public:
    shared_ptr<NodeB> b_ptr;
    ~NodeA() { cout << "NodeA Destroyed\n"; }
};

class NodeB {
public:
        // 使用 weak_ptr 替代 shared_ptr
    weak_ptr<NodeA> a_ptr;
    ~NodeB() { cout << "NodeB Destroyed\n"; }
};

int main() {
    shared_ptr<NodeA> a = make_shared<NodeA>();
    shared_ptr<NodeB> b = make_shared<NodeB>();

    cout << "a:" << a.use_count() << endl;
    cout << "b:" << b.use_count() << endl;
    cout << "a->b_ptr:" << a->b_ptr.use_count() << endl;;
    cout << "b->a_ptr:" << b->a_ptr.use_count() << endl;
    cout << "-------------------------------" << endl;
    a->b_ptr = b;
    b->a_ptr = a;
    cout << "a:" << a.use_count() << endl;
    cout << "b:" << b.use_count() << endl;
    cout << "a->b_ptr:" << a->b_ptr.use_count() << endl;
    cout << "b->a_ptr:" << b->a_ptr.use_count() << endl;

    // a 和 b 销毁时,引用计数正确归零
    return 0;  // 输出: NodeA Destroyed, NodeB Destroyed
}

编译以上代码,并且进行测试:

(base) blctrl@blctrl-s2:~/CPP_Program$ ./sp3
a:1
b:1
a->b_ptr:0
b->a_ptr:0
-------------------------------
a:1
b:2
a->b_ptr:2
b->a_ptr:1
NodeA Destroyed
NodeB Destroyed

对比表格

特性std::unique_ptrstd::shared_ptrstd::weak_ptr
所有权独占共享无(弱引用)
拷贝/赋值禁止拷贝,允许移动 (move)允许拷贝和赋值允许拷贝和赋值
内存释放时机指针销毁时引用计数归零时不参与计数,不影响释放时机
典型应用场景工厂模式、独占资源缓存、共享数据打破循环引用

注意事项

1)优先使用 make_unique 和 make_shared
避免直接使用 new,以提高性能和异常安全性:

// 推荐
auto ptr = std::make_shared<Data>();  
// 不推荐
std::shared_ptr<Data> ptr(new Data); 

 2)避免循环引用
若两个 shared_ptr 互相指向对方,会导致内存泄漏,需用 weak_ptr 解耦。

3)不要混合使用智能指针和裸指针
错误的裸指针操作可能导致悬空指针或重复释放:

int* raw_ptr = new int(5);
std::shared_ptr<int> sp1(raw_ptr);
// 错误!会导致重复释放
std::shared_ptr<int> sp2(raw_ptr); 

总结

  • unique_ptr:简单高效,用于明确所有权的场景。

  • shared_ptr:灵活共享,但需注意循环引用。

  • weak_ptr:辅助 shared_ptr,解决循环引用问题。

正确使用智能指针可显著提升代码安全性,减少内存管理错误。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值
OSZAR »