C++中有哪些智能指针,其作用分别是什么?

在C++中,智能指针是一种管理动态分配内存的类模板,它能够自动释放所管理的对象,从而避免内存泄漏。C++标准库中提供了几种常用的智能指针。

1. std::unique_ptr

独占所有权:确保同一时间只有一个unique_ptr指向一个特定的资源。
自动释放资源:当unique_ptr超出作用域时,会自动释放所管理的资源。
高效传递所有权:通过std::move可以将资源所有权转移。
不允许复制:只能通过移动语义进行传递。

#include <iostream>
#include <memory>

class MyClass {
public:
    MyClass() { std::cout << "MyClass Constructor\n"; }
    ~MyClass() { std::cout << "MyClass Destructor\n"; }
    void show() { std::cout << "MyClass show() function\n"; }
};

int main() {
    // 创建 unique_ptr 实例
    //std::unique_ptr<MyClass> ptr1(new MyClass()); //不推荐
    std::unique_ptr<MyClass> ptr1 = std::make_unique<MyClass>(); //推荐
    ptr1->show(); // 调用 MyClass 的成员函数

    //std::unique_ptr<MyClass> ptr2 = ptr1 // 此语句是错误的, unique_ptr 不支持复制,但支持移动语义
    std::unique_ptr<MyClass> ptr2 = std::move(ptr1); // 转移所有权

    // 此时 ptr1 不再拥有对象,尝试访问会导致未定义行为
    // ptr1->show(); // 不应执行此行

    // ptr2 仍然拥有对象,并在离开作用域时自动释放(unique_ptr类型的智能指针的指针变量是ptr2是局部变量,当它离开作用域时,它所指向的堆内存也会被释放)
    return 0; // MyClass Destructor 将在此处被调用
}

2. std::shared_ptr

共享所有权:允许多个shared_ptr共同拥有同一块内存。
引用计数:采用引用计数机制,当最后一个shared_ptr离开作用域或被重置时,所管理的资源会被释放。
解决共享资源管理问题:适用于多个对象需要共享同一资源的情况。

#include <iostream>
#include <memory>

class MyClass {
public:
    MyClass() { std::cout << "MyClass Constructor\n"; }
    ~MyClass() { std::cout << "MyClass Destructor\n"; }
    void show() { std::cout << "MyClass show() function\n"; }
};

int main() {
    // 创建 shared_ptr 实例
    //std::shared_ptr<MyClass> ptr1(new MyClass()); //不推荐
    std::shared_ptr<MyClass> ptr1 = std::make_shared<MyClass>(); //推荐
    //局部代码块
    {
        std::shared_ptr<MyClass> ptr2 = ptr1; // 复制,共享所有权
        ptr2->show(); // 调用 MyClass 的成员函数

        // 此时 MyClass 对象的引用计数为 2
    } // ptr2 离开作用域,引用计数减为 1

    ptr1->show(); // 再次调用 MyClass 的成员函数

    // ptr1 离开作用域,引用计数减为 0,对象被释放
    return 0; // MyClass Destructor 将在此处或稍后被调用(取决于实现)
}

3. std::weak_ptr

弱引用:不共享所有权,用于解决std::shared_ptr循环引用导致的内存泄漏问题。
不增加引用计数:可以从std::shared_ptr创建,但不会增加对象的引用计数。
检查对象状态:可以通过lock函数转换为std::shared_ptr,以安全地访问对象。

是一种不拥有资源的智能指针,它通常与 std::shared_ptr 配合使用,用于解决循环引用问题
#include <iostream>
#include <memory>

class MyClass {
public:
    MyClass() { std::cout << "MyClass Constructor\n"; }
    ~MyClass() { std::cout << "MyClass Destructor\n"; }
    void show() { std::cout << "MyClass show() function\n"; }
};

int main() {
    // 创建 shared_ptr 实例
    //std::shared_ptr<MyClass> sharedPtr(new MyClass()); //不推荐
	std::shared_ptr<MyClass> sharedPtr = std::make_shared<MyClass>(); //推荐
    // 创建 weak_ptr 实例,不增加引用计数
    std::weak_ptr<MyClass> weakPtr = sharedPtr;

    // 尝试锁定 weak_ptr,获取 shared_ptr
    std::shared_ptr<MyClass> lockedPtr = weakPtr.lock();
    if (lockedPtr) {
        lockedPtr->show(); // 调用 MyClass 的成员函数
    } else {//返回一个空的shared_ptr<MyClass>
        std::cout << "MyClass object has been destroyed\n";
    }

    // sharedPtr 离开作用域,引用计数减为 0,对象被释放
    return 0; // MyClass Destructor 将在此处被调用
}

在这里插入图片描述
先看一个C++中循环引用引起的问题代码示例:

#include <iostream>
#include <memory>

class B; // 前向声明

class A {
public:
    std::shared_ptr<B> ptrB; // A拥有一个指向B的shared_ptr
    ~A() { std::cout << "A destroyed\n"; }
};

class B {
public:
    std::shared_ptr<A> ptrA; // B拥有一个指向A的shared_ptr
    ~B() { std::cout << "B destroyed\n"; }
};

int main() {
    {
        std::shared_ptr<A> a = std::make_shared<A>();
        std::shared_ptr<B> b = std::make_shared<B>();
        a->ptrB = b;
        b->ptrA = a; // 形成循环引用

        // 此时,A类对象和B类对象的引用计数都为2(因为它们相互引用),所以它们都不会被销毁
    } // 离开作用域(虽然智能指针局部变量a和b被销毁,但他们所管理的对象并没有销毁),但由于循环引用,A类对象和B类对象并没有被销毁

    // 程序结束前,没有输出"A destroyed"和"B destroyed",说明a和b所指向的对象没有被释放
    return 0;
}

初始时,a是一个局部变量,a持有一个A对象的智能指针,b也是一个局部变量,b持有一个B对象的智能指针。
a->ptrB = b;执行时,A对象中的ptrB成员变量持有了b所指向的B对象的智能指针,此时,b所指向的B对象的引用计数增加到2(因为除了b本身,a->ptrB也在引用它)

b->ptrA = a;执行时,同样地,B对象中的ptrA成员变量持有了a所指向的A对象的智能指针。此时,a所指向的A对象的引用计数也增加到2(因为除了a本身,b->ptrA也在引用它)

std::weak_ptr如何打破循环引用及实例

#include <iostream>
#include <memory>

class B; // 前向声明

class A {
public:
    std::shared_ptr<B> ptrB; // A拥有一个指向B的shared_ptr
    ~A() { std::cout << "A destroyed\n"; }
};

class B {
public:
    std::weak_ptr<A> ptrA; // B拥有一个指向A的weak_ptr
    ~B() { std::cout << "B destroyed\n"; }
};

int main() {
    {
        std::shared_ptr<A> a = std::make_shared<A>();
        std::shared_ptr<B> b = std::make_shared<B>();
        a->ptrB = b;
        b->ptrA = std::weak_ptr<A>(a); // 注意这里是weak_ptr

        // 此时,a和b相互引用,但由于b使用的是weak_ptr,所以不会形成循环引用
    } // 离开作用域,a和b所管理的对象都被销毁

    // 如果没有weak_ptr,这里a和b会因为循环引用而无法被销毁
    return 0;
}

4. std::auto_ptr(已弃用)

独占所有权:类似于std::unique_ptr,但在C++11中被弃用。
所有权转移:赋值操作会将所有权转移,导致原指针失效。
不安全:在多指针场景下容易引发问题,因此被弃用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值