C++智能指针

C++智能指针简介

为什么要有智能指针

C++ 是一种支持多范式的编程语言,其中之一就是面向对象编程。面向对象编程的核心概念之一就是封装,即将数据和操作数据的函数组织在一起,形成一个类。类可以创建对象,对象是类的实例,具有类定义的属性和行为。对象在内存中占用空间,可以通过指针来访问和操作它们。

指针是一种变量,它存储了另一个变量的地址。通过指针,我们可以间接地访问和修改指向的变量。指针的优点是可以实现动态内存分配、多态性、泛型编程等功能,提高了程序的灵活性和效率。但是,指针也有缺点,例如:

  • 指针可能指向无效的内存地址,导致程序崩溃或出现未定义行为。例如在下个例子中,局部变量在该函数结束时释放,此时返回的指针变成了一个悬空指针,其指向的内存地址无效,引发错误。
int* functionA()
{
	int _a = 10;
	int* _p = &a;
	return _p;
}
  • 指针可能造成内存泄漏,即分配了内存但没有及时释放,占用了系统资源。由于 C++ 没有垃圾回收机制,导致通过 new 或 malloc 的内存没有 delete 和 free,导致内存泄漏。
  • 指针可能造成内存碎片,即分配和释放内存时产生了不连续的空闲区域,影响了内存利用率。
  • 指针可能造成所有权问题,即不清楚谁负责管理指向的内存,导致重复释放或遗漏释放。

智能指针是什么

为了解决这些问题,C++ 提供了一种特殊的指针类型,叫做智能指针。智能指针是一个类,它封装了一个原始指针,并重载了指针相关的操作符(如 * 和 ->)。智能指针的作用是自动管理指向的内存,当没有对象使用该内存时,就会自动释放它。这样,我们就不需要手动分配和释放内存,也不需要担心内存泄漏、无效指针、所有权问题等。

C++11 引入了三种智能指针类型:

  • std::unique_ptr
  • std::shared_ptr
  • std::weak_ptr

三种智能指针

std::unique_ptr

std::unique_ptr 是一种独占所有权的智能指针,它表示只有一个对象拥有指向的内存。当 std::unique_ptr 离开作用域时,它会自动删除指向的对象,并释放内存。std::unique_ptr 不能被复制或赋值给其他 std::unique_ptr,但可以被移动或转换为其他类型的智能指针。std::unique_ptr 的优点是简单高效,缺点是不能实现共享所有权。
下面是一个使用的例子:

#include <iostream>
#include <memory>
using namespace std;

class Test {
public:
    Test(int x) : data(x) {
        cout << "Test(" << data << ") constructed." << endl;
    }
    ~Test() {
        cout << "Test(" << data << ") destructed." << endl;
    }
    void show() {
        cout << "Test(" << data << ") show." << endl;
    }
private:
    int data;
};

int main() {
    // 使用 make_unique 创建一个 unique_ptr 对象
    unique_ptr<Test> p1 = make_unique<Test>(10);
    // 使用 -> 访问成员函数
    p1->show();
    // 使用 * 访问成员变量
    cout << "p1's data is " << (*p1).data << endl;
    // 使用 get 获取原始指针
    Test* ptr = p1.get();
    ptr->show();
    // 使用 move 转移所有权
    unique_ptr<Test> p2 = move(p1);
    // 此时 p1 为空
    if (p1 == nullptr) {
        cout << "p1 is nullptr." << endl;
    }
    // 此时 p2 拥有原来 p1 的内存
    p2->show();
    // 离开作用域时自动释放内存
    return 0;
}

输出结果

Test(10) constructed.
Test(10) show.
p1's data is 10
Test(10) show.
p1 is nullptr.
Test(10) show.
Test(10) destructed.

std::shared_ptr

std::shared_ptr 是一种共享所有权的智能指针,它表示多个对象可以共同拥有指向的内存。std::shared_ptr 通过引用计数来管理内存,每当有一个新对象使用该内存时,引用计数加一;每当有一个对象不再使用该内存时,引用计数减一。当引用计数为零时,就会自动删除指向的对象,并释放内存。std::shared_ptr 可以被复制和赋值给其他 std::shared_ptr 或 std::weak_ptr。std::shared_ptr 的优点是可以实现共享所有权和多态性,缺点是需要额外的开销来维护引用计数。

#include <iostream>
#include <memory>
using namespace std;

class Test {
public:
    Test(int x) : data(x) {
        cout << "Test(" << data << ") constructed." << endl;
    }
    ~Test() {
        cout << "Test(" << data << ") destructed." << endl;
    }
    void show() {
        cout << "Test(" << data << ") show." << endl;
    }
private:
    int data;
};

int main() {
    // 使用 make_shared 创建一个 shared_ptr 对象
    shared_ptr<Test> p1 = make_shared<Test>(20);
    // 使用 -> 访问成员函数
    p1->show();
    // 使用 * 访问成员变量
    cout << "p1's data is " << (*p1).data << endl;
    // 使用 get 获取原始指针
    Test* ptr = p1.get();
    ptr->show();
    // 使用 use_count 获取引用计数
    cout << "p1's use count is " << p1.use_count() << endl;
    // 使用 copy 构造函数或赋值运算符复制 shared_ptr 对象
    shared_ptr<Test> p2(p1);
    shared_ptr<Test> p3 = p1;
    // 此时引用计数增加
    cout << "p1's use count is " << p1.use_count() << endl;
    cout << "p2's use count is " << p2.use_count() << endl;
    cout << "p3's use count is " << p3.use_count() << endl;
    // 离开作用域时自动释放内存
    return 0;
}

输出:

Test(20) constructed.
Test(20) show.
p1's data is 20
Test(20) show.
p1's use count is 1
p1's use count is 3
p2's use count is 3
p3's use count is 3
Test(20) destructed.

std::weak_ptr

std::weak_ptr 是一种观察者指针,它不影响内存的生命周期,它需要和 shared_ptr 一起使用,可以防止循环引用的问题。

#include <iostream>
#include <memory>
using namespace std;

class Test {
public:
    Test(int x) : data(x) {
        cout << "Test(" << data << ") constructed." << endl;
    }
    ~Test() {
        cout << "Test(" << data << ") destructed." << endl;
    }
    void show() {
        cout << "Test(" << data << ") show." << endl;
    }
private:
    int data;
};

int main() {
    // 使用 make_shared 创建一个 shared_ptr 对象
    shared_ptr<Test> p1 = make_shared<Test>(30);
    // 使用 weak_ptr 来观察 shared_ptr 对象,不影响引用计数
    weak_ptr<Test> p2(p1);
    // 使用 expired 判断 shared_ptr 对象是否还存在
    if (!p2.expired()) {
        cout << "p2 is not expired." << endl;
        // 使用 lock 获取一个临时的 shared_ptr 对象,可以访问内存
        shared_ptr<Test> p3 = p2.lock();
        p3->show();
        // 离开作用域时释放临时的 shared_ptr 对象,不影响原来的 shared_ptr 对象
    }
    // 重置 shared_ptr 对象,释放内存
    p1.reset();
    // 此时 weak_ptr 对象已经过期,不能访问内存
    if (p2.expired()) {
        cout << "p2 is expired." << endl;
        // 使用 lock 获取一个空的 shared_ptr 对象,不能访问内存
        shared_ptr<Test> p4 = p2.lock();
        if (p4 == nullptr) {
            cout << "p4 is nullptr." << endl;
        }
    }
    return 0;
}

输出:

Test(30) constructed.
p2 is not expired.
Test(30) show.
Test(30) destructed.
p2 is expired.
p4 is nullptr.

总结

智能指针是一种可以自动管理内存的指针,它可以避免手动调用 new 和 delete 来分配和释放内存。C++ 标准库提供了四种智能指针:auto_ptr、unique_ptr、shared_ptr 和 weak_ptr。其中 auto_ptr 已经被废弃,不建议使用。智能指针的使用方法和原始指针类似,但需要注意一些细节和注意事项。智能指针可以提高程序的安全性和效率,是 C++ 程序员必备的工具之一。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值