前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C++智能指针的用法

C++智能指针的用法

作者头像
SarPro
发布2024-02-20 13:17:02
1160
发布2024-02-20 13:17:02
举报
文章被收录于专栏:【计网】Cisco

1. 智能指针

智能指针是一种在C++中用于管理动态分配内存的工具,它们提供了更安全和方便的方式来管理内存资源,以避免内存泄漏和资源管理错误。

常用的智能指针类型包括:

  1. std::shared_ptr共享指针,用于多个智能指针共享相同的资源,引用计数方式来管理资源的生命周期。当最后一个引用离开作用域时,资源被释放。
  2. std::unique_ptr唯一指针,表示独占所有权的指针,不能被复制或共享。当 std::unique_ptr 离开作用域时,它拥有的资源会被自动释放。
  3. std::weak_ptr弱指针,用于协助 std::shared_ptr 来解决循环引用问题。它不增加引用计数,不影响资源的生命周期,但可以用于检查资源是否仍然有效。

区别

std::shared_ptr:

允许多个 std::shared_ptr 共享同一块内存。

跟踪引用计数,当最后一个 std::shared_ptr 对象离开作用域时,它会自动释放内存。

可以使用 std::make_shared 创建对象并返回一个 std::shared_ptr。

适用于共享资源的情况,例如多个对象需要访问同一块内存。

代码语言:javascript
复制
std::shared_ptr<int> sharedPtr = std::make_shared<int>(42);

std::unique_ptr:

拥有唯一所有权,不能被复制。当 std::unique_ptr 离开作用域时,它会自动释放内存。

没有引用计数,通常比 std::shared_ptr 更快。

可以使用 std::make_unique 创建对象并返回一个 std::unique_ptr。

适用于独占资源的情况,例如动态分配的对象。

代码语言:javascript
复制
std::unique_ptr<int> uniquePtr = std::make_unique<int>(42);

std::weak_ptr:

用于解决 std::shared_ptr 的循环引用问题。std::weak_ptr 不能直接访问所管理的内存,需要将其转换为 std::shared_ptr 才能访问内存。

本身无引用计数,但为了协助 std::shared_ptr 进行引用计数管理而存在的。

不提供 std::make_weak 函数。通常与 std::shared_ptr 一起使用,用于避免循环引用

代码语言:javascript
复制
std::shared_ptr<int> shared = std::make_shared<int>(42);
std::weak_ptr<int> weak = shared;
std::shared_ptr<int> sharedAgain = weak.lock();  // 将 weak 转换为 shared_ptr

总结:

  • std::shared_ptr 适用于多个智能指针需要共享同一块内存的情况 / 可以使用 std::make_shared 创建对象并返回一个 std::shared_ptr / 跟踪引用计数
  • std::unique_ptr 适用于独占资源的情况,通常更高效 / 可以使用 std::make_unique 创建对象并返回一个 std::unique_ptr / 没有引用计数,通常比 std::shared_ptr 更快。
  • std::weak_ptr 用于解决循环引用问题,通常与 std::shared_ptr 配合使用 / 不提供 std::make_weak 函数,通常与 std::shared_ptr 一起使用 / 本身无引用计数,但为了协助 std::shared_ptr 进行引用计数管理而存在的。

2. 优势

  1. 自动内存管理:智能指针自动处理资源的分配和释放,减少了手动管理内存的需求。这有助于防止内存泄漏和释放已释放的内存,提高了程序的稳定性。
  2. 安全性:智能指针提供了更安全的资源管理方式,减少了内存管理错误的发生,如悬挂指针、重复释放等。它们有助于消除许多常见的编程错误。
  3. 生命周期管理std::shared_ptr 使用引用计数来管理资源的生命周期,确保只有在不再被引用时才会释放资源。这有助于避免在资源仍然在使用时释放它。
  4. 简化代码:使用智能指针可以简化代码,因为它们自然地表达了资源的所有权和生命周期。这提高了代码的可读性和可维护性。
  5. 自动资源释放std::unique_ptr 保证资源的独占所有权,当它超出作用域时会自动释放资源。这有助于确保资源不会泄漏。
  6. 共享资源std::shared_ptr 允许多个智能指针共享相同的资源,这可以减少内存使用,同时确保资源在不再被引用时被释放。

3. 用法

3.1 std::shared_ptr共享指针

std::shared_ptr 是 C++ 标准库中的一个智能指针,用于管理动态分配的对象的生命周期。允许多个 shared_ptr 实例共享同一个对象,当最后一个 shared_ptr 实例离开作用域时,将自动释放分配的资源。

1. 使用需导入头文件

代码语言:javascript
复制
#include <memory>

2. 创建 std::shared_ptr:示例创建了一个 std::shared_ptr,并将其初始化为一个整数类型的动态分配对象,该对象的值为 42。std::make_shared 是一个创建 std::shared_ptr 的便捷函数,它分配内存并返回一个智能指针。

代码语言:javascript
复制
std::shared_ptr<int> sharedInt = std::make_shared<int>(42);

3. 共享 std::shared_ptr:sharedInt 和 anotherSharedInt 指向相同的整数对象,它们共享资源。

代码语言:javascript
复制
std::shared_ptr<int> anotherSharedInt = sharedInt;

4. 访问共享的对象:通过解引用 std::shared_ptr,你可以访问共享对象的值,就像使用原始指针一样。

代码语言:javascript
复制
int value = *sharedInt;
int anotherValue = *anotherSharedInt;

5. 自动资源管理: 当 std::shared_ptr 没有引用时,它会自动释放分配的资源,无需手动释放内存。这可以有效地避免内存泄漏。

代码语言:javascript
复制
sharedInt.reset(); // 释放 sharedInt 指向的资源

6. 检查引用计数: std::shared_ptr 使用引用计数来跟踪有多少个 std::shared_ptr 实例共享资源。可以使用 use_count() 方法来检查引用计数:

代码语言:javascript
复制
int count = sharedInt.use_count();

示例程序

代码语言:javascript
复制
#include <iostream>
#include <memory>

int main() {
    // 创建一个 std::shared_ptr,共享整数对象
    std::shared_ptr<int> sharedInt = std::make_shared<int>(42);

    // 共享相同的对象
    std::shared_ptr<int> anotherSharedInt = sharedInt;

    // 访问共享的对象
    int value = *sharedInt;
    int anotherValue = *anotherSharedInt;

    std::cout << "sharedInt: " << value << std::endl;
    std::cout << "anotherSharedInt: " << anotherValue << std::endl;

    // 检查引用计数
    int count = sharedInt.use_count();
    std::cout << "Reference count: " << count << std::endl;

    // 释放 sharedInt 指向的资源
    sharedInt.reset();

    // 再次检查引用计数
    count = anotherSharedInt.use_count();
    std::cout << "Reference count after reset: " << count << std::endl;

    return 0;
}

示例中,创建了两个 std::shared_ptr 实例,它们都指向相同的整数对象。我们访问了这两个智能指针,然后释放了一个智能指针的资源。最后检查了引用计数以验证资源的释放。这个示例展示了 std::shared_ptr 如何自动管理资源,确保资源在不再需要时被正确释放。

3.2 std::unique_ptr唯一指针

std::unique_ptr 是 C++ 标准库中的另一个智能指针类,用于管理动态分配的对象,但与 std::shared_ptr 不同,std::unique_ptr 确保同一时刻只有一个指针可以拥有对动态对象的唯一所有权,因此它适用于独占所有权的情况。当 std::unique_ptr 超出范围或被显式地释放时,它将自动释放分配的资源。

1. 包含头文件

代码语言:javascript
复制
#include <memory>

2. 创建 std::unique_ptr:示例使用 std::make_unique 创建 std::unique_ptr,并将其初始化为一个整数类型的动态分配对象,该对象的值为 42。

代码语言:javascript
复制
std::unique_ptr<int> uniqueInt = std::make_unique<int>(42);

3. 唯一所有权:示例将 uniqueInt 的所有权转移给 anotherUniqueInt,因为 std::unique_ptr 确保同一时刻只有一个指针拥有对动态对象的唯一所有权。

代码语言:javascript
复制
std::unique_ptr<int> anotherUniqueInt = std::move(uniqueInt);

4. 访问唯一的对象:可以像使用原始指针一样解引用 std::unique_ptr,以访问唯一的对象。

代码语言:javascript
复制
int value = *anotherUniqueInt;

5. 自动资源管理:std::unique_ptr 在超出范围时或被显式释放时,会自动释放分配的资源,无需手动释放内存。

代码语言:javascript
复制
anotherUniqueInt.reset(); // 释放 anotherUniqueInt 指向的资源

6. 检查是否为空:可以使用条件语句来检查 std::unique_ptr 是否为空,即是否指向有效的对象。

代码语言:javascript
复制
if (!anotherUniqueInt) {
    std::cout << "anotherUniqueInt is null" << std::endl;
}

示例程序:示例中std::unique_ptr 确保了对整数对象的唯一所有权,并在合适的时候释放了资源,避免了内存泄漏。

代码语言:javascript
复制
#include <iostream>
#include <memory>

int main() {
    // 创建一个 std::unique_ptr,拥有整数对象的唯一所有权
    std::unique_ptr<int> uniqueInt = std::make_unique<int>(42);

    // 唯一所有权转移
    std::unique_ptr<int> anotherUniqueInt = std::move(uniqueInt);

    // 访问唯一的对象
    int value = *anotherUniqueInt;
    std::cout << "anotherUniqueInt: " << value << std::endl;

    // 释放 anotherUniqueInt 指向的资源
    anotherUniqueInt.reset();

    // 检查是否为空
    if (!anotherUniqueInt) {
        std::cout << "anotherUniqueInt is null" << std::endl;
    }

    return 0;
}

3.3 std::weak_ptr弱指针

std::weak_ptr 是 C++ 标准库中的另一种智能指针类,它用于解决 std::shared_ptr 的循环引用问题。std::weak_ptr 允许你观察 std::shared_ptr 指向的对象,但不拥有该对象,因此不会增加引用计数,也不会影响对象的生存期。这对于解决对象之间相互引用导致的内存泄漏问题非常有用。

1. 包含头文件

代码语言:javascript
复制
#include <memory>

2. 创建 std::shared_ptr 和 std::weak_ptr:示例创建了 std::shared_ptr 来管理整数对象,并使用 std::weak_ptr 来观察该对象。

代码语言:javascript
复制
std::shared_ptr<int> sharedInt = std::make_shared<int>(42);
std::weak_ptr<int> weakInt = sharedInt;

3. 使用 std::weak_ptr

代码语言:javascript
复制
if (auto shared = weakInt.lock()) {
    // 使用 shared 来访问对象
    int value = *shared;
    std::cout << "Weak pointer is valid: " << value << std::endl;
} else {
    std::cout << "Weak pointer is expired" << std::endl;
}

使用 std::weak_ptr 的 lock() 方法,可以尝试将其转换为一个有效的 std::shared_ptr。如果 std::weak_ptr 指向的对象仍然存在,lock() 将返回一个有效的 std::shared_ptr,否则返回一个空的 std::shared_ptr。

4. 弱引用的对象释放: std::shared_ptr 所有权结束后,std::weak_ptr 不会阻止对象的释放。

代码语言:javascript
复制
sharedInt.reset(); // 释放 sharedInt 指向的资源

if (auto shared = weakInt.lock()) {
    // shared 现在为空
    std::cout << "Weak pointer is still valid: " << *shared << std::endl;
} else {
    std::cout << "Weak pointer is expired" << std::endl;
}

即使 sharedInt 被释放,std::weak_ptr 仍然可以安全地检查是否指向一个有效的对象。

总之,std::weak_ptr 是一种用于解决 std::shared_ptr 循环引用问题的智能指针,它允许观察共享对象,但不拥有对象的所有权,从而避免了内存泄漏。

示例程序

代码语言:javascript
复制
#include <iostream>
#include <memory>

int main() {
    // 创建一个 std::shared_ptr 来管理整数对象
    std::shared_ptr<int> sharedInt = std::make_shared<int>(42);

    // 创建一个 std::weak_ptr 来观察 sharedInt
    std::weak_ptr<int> weakInt = sharedInt;

    // 使用 std::weak_ptr 来访问对象
    if (auto shared = weakInt.lock()) {
        int value = *shared;
        std::cout << "Weak pointer is valid: " << value << std::endl;
    } else {
        std::cout << "Weak pointer is expired" << std::endl;
    }

    // 释放 sharedInt 的资源
    sharedInt.reset();

    // 再次使用 std::weak_ptr
    if (auto shared = weakInt.lock()) {
        std::cout << "Weak pointer is still valid: " << *shared << std::endl;
    } else {
        std::cout << "Weak pointer is expired" << std::endl;
    }

    return 0;
}

示例中,std::weak_ptr 允许观察 sharedInt,并在释放 sharedInt 后仍然可以安全地检查其有效性。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-11-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 智能指针
  • 2. 优势
  • 3. 用法
    • 3.1 std::shared_ptr:共享指针
      • 3.2 std::unique_ptr:唯一指针
        • 3.3 std::weak_ptr:弱指针
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档