C++11:智能指针(一)

目录

1、智能指针含义

2、unique_ptr

3、shared_ptr:

4、weak_ptr


本篇文章主要讲智能指针的基本知识,要是会,可以跳过去看指针智能实战示例。

C++11:智能指针(二)实战篇(附上实例)-CSDN博客

1、智能指针含义

(1)C++智能指针是一种用于管理动态内存的指针,可以自动进行内存管理,避免了手动管理内存所带来的问题。

(2)智能指针的核心思想是资源分配即初始化(RAII),即在对象的构造函数中进行资源分配,在对象的析构函数中进行资源释放。智能指针通过重载指针操作符和析构函数来实现资源的自动释放,从而避免了内存泄漏和野指针的问题。

(3)C++中的智能指针主要有以下几种:unique_ptr、weak_ptr、weak_ptr;

2、unique_ptr

unique_ptr是一种独占式智能指针,即每个unique_ptr指向的内存只能被一个unique_ptr拥有,不能被其他unique_ptr或者普通指针所共享。当unique_ptr被销毁时,它所指向的内存也会被自动释放。

(1)unique_ptr常用的api:

1. 构造函数:unique_ptr ptr(new T)、unique_ptr ptr(nullptr)、unique_ptr ptr(std::move(other_ptr));
2. 拷贝构造函数:unique_ptr ptr2 = std::move(ptr1);
3. 移动构造函数:unique_ptr ptr2 = std::move(ptr1);
4. 析构函数:当unique_ptr对象离开作用域时,会自动调用析构函数,释放所管理的对象;
5. 重载*和->操作符:*ptr和ptr->member都可以访问所管理的对象;
6. reset函数:释放当前所管理的对象,并指向一个新的对象;
7. release函数:释放unique_ptr对象对所管理的对象的所有权,返回指向所管理的对象的指针;
8. get函数:返回所管理的对象的指针;
9. operator bool函数:判断unique_ptr是否为空,即是否管理了一个对象;
10. operator=函数:将一个unique_ptr对象赋值给另一个unique_ptr对象;
11. make_unique函数:用于创建一个unique_ptr对象,并指向一个新的对象。

(2)unique_ptr示例:它的拷贝构造和赋值运算符都是被删除的,所以它只能被移动。

#include 
#include 

using namespace std;

int main() 
{
    unique_ptr p1(new int(42));// 创建一个unique_ptr,指向int类型的动态内存,初始值为42
    cout << *p1 << endl;// 输出42

    *p = 100; // 修改动态内存中的值
    std::cout << *p << std::endl; // 输出100

    unique_ptr p2 = move(p1);
    cout << *p2 << endl;

    // unique_ptr p3 = p2; // 编译错误,不能拷贝构造

    unique_ptr p4;
    // p4 = p2; // 编译错误,不能赋值

    return 0;
}

3、shared_ptr

shared_ptr是一种共享式智能指针,即多个shared_ptr可以共同拥有同一个内存资源。每个shared_ptr内部有一个计数器,记录有多少个shared_ptr指向同一个内存资源,当计数器为0时,内存资源被自动释放。

(1)share_ptr常用的api:

1. std::shared_ptr:定义一个指向类型为T的共享指针。
2. std::make_shared(args):创建一个共享指向类型为T的对象,并使用args构造它。
3. std::shared_ptr p1:创建一个名为p1的共享指针,指向类型为T的对象。
4. p1.reset():释放p1指向的对象。
5. p1.reset(new T(args)):创建一个新的类型为T的对象,并将p1指向它。
6. p1.use_count():返回与p1共享同一对象的指针数。
7. p1.unique():如果p1是对象的唯一所有者,则返回true;否则返回false。
8. p1.get():返回p1指向的对象的指针。
9. p1.swap(p2):交换p1和p2指向的对象。
10. std::enable_shared_from_this:允许一个对象在其生命周期内创建一个共享指针。

(2)使用方法:

std::shared_ptr p1(new int(42)); // 创建一个shared_ptr,指向int类型的动态内存,初始值为42
std::shared_ptr p2 = p1; // p2和p1共享同一个内存资源
std::cout << *p1 << " " << *p2 << std::endl; // 输出42 42
*p1 = 100; // 修改动态内存中的值
std::cout << *p1 << " " << *p2 << std::endl; // 输出100 100

4、weak_ptr

weak_ptr是弱引用智能指针,它指向一个shared_ptr所管理的内存资源,但是不会增加内存资源的引用计数。当所指向的内存资源被释放时,weak_ptr会自动变成空指针。是shared_ptr的一种补充,可以解决shared_ptr的循环引用问题,但是不能直接访问对象,需要先将其转换为shared_ptr。

(1)weak_ptr相关的api:​​​​​​

1. 构造函数:weak_ptr()、weak_ptr(const shared_ptr& r)、weak_ptr(const weak_ptr& r)、weak_ptr(weak_ptr&& r) noexcept
2. 赋值运算符:operator=(const weak_ptr& r)、operator=(weak_ptr&& r) noexcept、operator=(const shared_ptr& r)
3. 释放资源:reset()、swap(weak_ptr& r) noexcept
4. 获取资源:lock()、expired()、use_count()
5. 比较运算符:operator==、operator!=、operator<、operator<=、operator>、operator>=
6. 类型转换:template operator weak_ptr() const noexcept
7. 其他:owner_before(const weak_ptr& r) const、hash>、make_weak、enable_shared_from_this
8. 注意:weak_ptr 不能直接访问资源,必须使用 lock() 方法获得 shared_ptr,然后才能访问资源。expired() 方法用于判断 weak_ptr 指向的资源是否已经被销毁。

(2)shared_ptr的循环引用问题:指的是在使用shared_ptr时,两个或多个对象相互引用,导致它们之间形成了一个循环引用的情况。这种情况下,当所有的shared_ptr都超出作用域时,对象并不会被正确地释放,从而导致内存泄漏。

例如,假设有两个对象A和B,它们都持有对方的shared_ptr,形成了循环引用。当程序结束时,A和B的引用计数都为1,导致它们都不会被正确地释放,造成内存泄漏。

        为了避免shared_ptr的循环引用问题,可以使用weak_ptr来解决。weak_ptr是一种弱引用,它不会增加对象的引用计数,也不会阻止对象的析构。当需要访问对象时,可以通过lock()方法将weak_ptr转换为shared_ptr,如果对象已经被释放,则返回一个空的shared_ptr。这样,即使存在循环引用,对象也能被正确地释放,避免内存泄漏。

(3)使用方法:

std::shared_ptr p(new int(42)); // 创建一个shared_ptr,指向int类型的动态内存,初始值为42
std::weak_ptr wp = p; // 创建一个weak_ptr,指向p所管理的内存资源
std::cout << *wp.lock() << std::endl; // 输出42,使用lock()函数获取weak_ptr指向的内存资源的shared_ptr
p.reset(); // 释放p所管理的内存资源
if(wp.expired()) // 判断wp是否为空指针
    std::cout << "wp is null" << std::endl; // 输出wp is null

(4)什么时候使用share_ptr和weak_ptr

1) 使用 shared_ptr 是为了共享一个对象的所有权,使多个对象可以同时引用该对象。当我们需要一个对象能够被多个对象共享时,我们通常使用 shared_ptr。

#include 
#include 

int main() {
    std::shared_ptr sp1 = std::make_shared(10);
    std::shared_ptr sp2 = sp1;
    std::cout << "sp1 use count: " << sp1.use_count() << std::endl;  // 输出2,说明共享同一个资源
    std::cout << "sp2 use count: " << sp2.use_count() << std::endl;  // 输出2,说明共享同一个资源
    return 0;
}

2) 使用 weak_ptr 是为了避免循环引用导致的内存泄漏问题。当我们需要在一个对象中引用另一个对象时,而另一个对象也需要引用该对象时,我们可以使用 weak_ptr,也就是当需要一个智能指针观察某个资源的生命周期,但不拥有该资源时,使用weak_ptr;通常在实现缓存、观察者模式等场景下使用 weak_ptr。

#include 
#include 

int main() {
    std::shared_ptr sp1 = std::make_shared(10);
    std::weak_ptr wp1 = sp1;
    std::cout << "sp1 use count: " << sp1.use_count() << std::endl;  // 输出1,说明sp1拥有资源
    std::cout << "wp1 use count: " << wp1.use_count() << std::endl;  // 输出1,说明wp1未拥有资源
    if (auto sp2 = wp1.lock()) // 使用lock()方法获取资源的shared_ptr
    {  
        std::cout << "wp1 is valid." << std::endl;
        std::cout << "sp2 use count: " << sp2.use_count() << std::endl;  // 输出2,说明共享同一个资源
    } 
    else 
    {
        std::cout << "wp1 is invalid." << std::endl;
    }
    return 0;
}

总结:

智能指针是C++11中新增的重要特性,它可以有效地避免内存泄漏和空指针问题,提高代码的安全性、程序的健壮性和可维护性。在实际开发中,应该根据具体的场景选择不同类型的智能指针,合理地管理动态内存。

注意:智能指针并不能完全取代手动管理内存,对于一些特殊场景仍需要手动管理内存。

你可能感兴趣的:(#,c++新特性,c++,开发语言,jvm,1024程序员节)