c++ 智能指针的使用

发布时间:2024年01月17日

为了解决传统指针相关的安全问题,C++11之后推出了智能指针。

如 std::unique_ptr,std::shared_ptr 和 std::weak_ptr。

它们会自动管理内存,减少了内存泄漏和其他常见错误的风险。

当你需要直接操纵内存地址时,指针仍然是有用的,但在现代C++编程实践中,应该尽量使用智能指针来管理动态内存。

std::unique_ptr

一个独占所有权的智能指针。一个 std::unique_ptr 对象拥有其指向的资源的唯一所有权。当 std::unique_ptr 被销毁时(通常是其所在的作用域结束时),它指向的对象也会被自动销毁。std::unique_ptr 不能被复制,但可以移动。
#include <memory>
void someFunction() {
	// 创建一个 unique_ptr 指向一个整数
	std::unique_ptr<int> uptr(new int(10));
	// 创建一个 unique_ptr 使用工厂函数 std::make_unique (C++14及以后)
	//使用 std::make_unique 创建 std::unique_ptr 更为偏好(C++14 之后),因为这提供了更好的异常安全性
	auto uptr2 = std::make_unique<int>(20);
	// 使用 -> 和 * 运算符访问 unique_ptr 的内容
	*uptr = 5;
	std::cout << *uptr; // 打印 5
	std::cout << *uptr2; // 打印 20
	// 移动 unique_ptr 的所有权
	std::unique_ptr<int> uptr3 = std::move(uptr2);
	// 此时 uptr2 为空,并且 uptr3 拥有原本 uptr2 指向的资源
}
void someFunction1() {
    // 创建一个 unique_ptr
    std::unique_ptr<int> uptr(new int(10));
    // 访问值
    std::cout << *uptr << std::endl;
    // 转移所有权
    std::unique_ptr<int> uptr2 = std::move(uptr);
    // 此时 uptr 为空,uptr2 独占所有权
    if (uptr) {
        std::cout << "uptr is not null!" << std::endl;
    }
    // uptr2 在函数结束时自动释放内存
}

std::shared_ptr

一个共享所有权的智能指针。多个 std::shared_ptr 可以指向相同的资源。资源的最后一个所有者被销毁时,指向的对象才会被销毁。 std::shared_ptr 内部使用一个引用计数机制来追踪多少个 shared_ptr 处于活动状态。
#include <memory>

class MyClass { /* ... */ };
// 创建一个 shared_ptr 指向 MyClass 的一个实例
std::shared_ptr<MyClass> sptr1(new MyClass());
// 使用工厂函数 std::make_shared (推荐,速度更快且安全)
auto sptr2 = std::make_shared<MyClass>();
// 复制 shared_ptr 增加引用计数
std::shared_ptr<MyClass> sptr3 = sptr2;
// 函数参数或返回值
void func(std::shared_ptr<MyClass> sptr) { /* ... */ }
std::shared_ptr<MyClass> getSharedPtr() { return sptr1; }
// sptr1, sptr2, sptr3 指向的 MyClass 实例将在最后一个使用它的 shared_ptr 被销毁时自动释放

void anotherFunction() {
    // 使用 make_shared 创建 shared_ptr
    auto sptr = std::make_shared<int>(10);
    {
        // 创建另一个 shared_ptr 共享所有权
        std::shared_ptr<int> sptr2 = sptr;
        // 此时引用计数为 2
    } // sptr2 离开作用域,引用计数减为 1
    // sptr 仍然有效
    std::cout << *sptr << std::endl;
    // 当 sptr 离开作用域,指向的整数将被删除
}

std::weak_ptr

一种非独占所有权的智能指针,它指向由 std::shared_ptr 管理的对象。与 shared_ptr 不同,weak_ptr 不会增加对象的引用计数。这意味着 weak_ptr 不会阻止其指向的对象被销毁。它通常被用来解决 std::shared_ptr 之间可导致循环引用和内存泄漏的问题
#include <memory>
void thirdFunction1() {
	std::shared_ptr<int> sptr = std::make_shared<int>(42);
	std::weak_ptr<int> wptr = sptr; // wptr 指向 sptr 所指的对象,但不增加引用计数
	// 检查 weak_ptr 所指的对象是否仍然存在
	if (auto temp = wptr.lock()) {
	    std::cout << *temp << '\n'; // 使用 temp 这个 shared_ptr 访问数据
	} else {
	    std::cout << "对象已被销毁\n";
	}
	// 当最后一个 shared_ptr 被销毁时,即使还有 weak_ptr 指向对象,对象也会被释放
}
void thirdFunction() {
    auto sptr = std::make_shared<int>(10);
    // 创建一个 weak_ptr 来观察
    std::weak_ptr<int> wptr = sptr;
    // 从 weak_ptr 创建一个 shared_ptr 来使用资源
    if (std::shared_ptr<int> sptrCopy = wptr.lock()) {
        // 使用 sptrCopy
        std::cout << *sptrCopy << std::endl;
    } else {
        std::cout << "资源已经被释放了" << std::endl;
    }
    // 由于没有改变引用计数,sptr 仍然可用
}

使用注意事项

1、避免裸指针,优先使用智能指针来管理资源;
2、避免使用 newdelete,转而使用 std::make_unique 和 std::make_shared 来创建智能指针。
3、当使用 unique_ptr 时,表明对象拥有唯一所有权,通过 std::move() 来转移所有权;
4、使用 shared_ptr 来共享资源时,来共享对象所有权或实现观察者模式,要注意避免循环引用,否则可能导致内存泄漏;
5、使用 weak_ptr 来窥视 shared_ptr 或打破循环引用,避免 std::shared_ptr 的循环引用问题;
6、当需要传递智能指针给函数或从函数返回智能指针时,如果不需要转移所有权,则应传递引用(const std::unique_ptr<T>&const std::shared_ptr<T>&)。这样避免增加引用计数或者导致不必要的所有权转移。
7、总要确保对于任何资源的管理都是明确的,避免资源泄露。

作为学习的知识点记录分享,欢迎大家补充

文章来源:https://blog.csdn.net/weixin_43779276/article/details/135618328
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。