C++智能指针

智能指针是一种C++语言中的智能化内存管理工具,是一种用来管理动态分配的对象的指针。它的作用是自动化管理内存的分配和释放,以避免内存泄漏和悬空指针的问题。
智能指针是C++11标准中引入的一个新特性,它们是通过模板类来实现的。
C++中的智能指针主要有三种:unique_ptr、shared_ptr和weak_ptr。

  1. unique_ptr是独占所有权的指针,只能有一个unique_ptr指向同一个对象,当unique_ptr被销毁时,它所指向的对象也会被销毁。
  2. shared_ptr是共享所有权的指针,多个shared_ptr可以指向同一个对象,当最后一个shared_ptr被销毁时,它所指向的对象也会被销毁。
  3. weak_ptr是一种弱引用,它不会增加对象的引用计数,可以用来解决shared_ptr的循环引用问题。

使用智能指针可以避免手动管理内存和手动释放对象的问题,可以提高代码的可靠性和安全性。但是需要注意的是,使用智能指针也可能会带来一些性能上的损失,因为智能指针需要进行额外的计数和管理工作。

shared_ptr(共享指针):

一种共享指针,是多线程安全的智能指针,它可以使多个指针拥有对同一个对象的控制权,即多个指针可以共享同一个对象。
当最后一个shared_ptr对象被销毁时,它所管理的对象也会被销毁。
使用shared_ptr要特别注意循环引用的问题,即两个对象相互引用,导致无法被销毁。
同时,shared_ptr还提供了自定义删除器的功能,可以在释放资源时调用自定义的函数。

每个 shared_ptr 对象在内部指向两个内存位置:
1、指向对象的指针。
2、用于控制引用计数数据的指针。
每当有一个新的shared_ptr对象指向同一块内存时,引用计数会自增,当某个shared_ptr对象超出作用域或被显式地设置为nullptr时,引用计数会自减,当引用计数降为0时,shared_ptr便会自动释放其持有的内存。

创建 shared_ptr 时注意事项:

  1. 不要使用一个原始指针初始化多个shared_ptr
int *num = new int(23);
std::shared_ptr<int> p1(num);
std::shared_ptr<int> p2(p1);  // 正确使用方法
std::shared_ptr<int> p3(num); // 不推荐
  1. 在使用 shared_ptr 时,应该优先使用 make_shared 函数来创建 shared_ptr,避免手动管理资源导致的错误;
std::shared_ptr<int> ptr_1 = make_shared<int>();
std::shared_ptr<int> ptr_2 (ptr_1);
  1. 不要用栈中的指针构造 shared_ptr 对象
#include<iostream>
#include<memory>
int main() {
    int x = 12;
    std::shared_ptr<int> ptr(&x);
    return 0;
}

使用shared_ptr时需要注意以下几点:

  1. 不要将原始指针和shared_ptr混合使用,否则也可能导致内存泄漏或崩溃。
  2. 不要使用一个原始指针初始化多个shared_ptr 即不要在同一个对象上使用多个shared_ptr,否则会导致计数器混乱,内存泄漏或崩溃。
  3. 当从一个shared_ptr对象中获取对象指针时,应该使用get()成员函数,而不是直接访问shared_ptr对象中的指针。
  4. 当使用循环引用时,多个shared_ptr对象相互持有对方的指针,可能会导致内存泄漏问题。为此,可以使用weak_ptr来解决循环引用问题。
#include <memory>
class MyClass {
public:  
    std::shared_ptr<MyClass> another_instance;  
    MyClass() {std::cout << "Creating MyClass instance\n";  }  
    ~MyClass() {std::cout << "Destroying MyClass instance\n";  }
};
int main() {  
    std::shared_ptr<MyClass> instance1 =
      std::make_shared<MyClass>();  
    std::shared_ptr<MyClass> instance2 =
      std::make_shared<MyClass>();  
    instance1->another_instance = instance2;
    instance2->another_instance = instance1;  
    return 0;
}
// 这段代码创建了两个MyClass对象,并使它们相互引用。这种做法的弊端在于,两个对象的引用计数永远无法降为0,因为它们相互引用。因此,这会导致内存泄漏,直到程序结束。要避免这种情况,应该避免使用shared_ptr相互引用,或者使用weak_ptr来引用。
  1. 当将shared_ptr对象传递给函数或返回一个shared_ptr对象时,建议使用传值方式或者使用std::move()函数,而不是传递指针。
  2. 不要将shared_ptr传递给函数,除非函数需要共享所有权。更好的做法是传递一个const引用或原始指针。
  3. 不要将shared_ptr存储在容器中,例如std::vector。
    shared_ptr存储在容器中的主要弊端是可能导致内存泄漏和悬空指针的问题。当共享指针退出作用域时,如果没有正确的释放内存,它所指向的内存块将一直存在于堆内存中,导致内存泄漏。而当容器中的元素被删除或容器本身被销毁时,在容器中的shared_ptr对象也会被自动删除,这可能导致悬空指针。针对这个问题,可以使用std::weak_ptr或std::unique_ptr来避免内存泄漏和悬空指针的问题。

shared_ptr自定义删除器功能

使用场景:

  1. 动态分配的内存不是通过 new 关键字分配的,而是通过其他方式分配的,例如 mmap、malloc 等。
  2. 动态分配的内存需要在释放之前执行一些额外的操作,例如释放资源时需要关闭文件句柄、释放锁等。
    示例代码:
#include <iostream>
#include <memory>

void my_deleter(int* p) {
    std::cout << "Deleting memory at " << p << std::endl;
    delete p;
}

int main() {
    std::shared_ptr<int> p(new int(10), my_deleter);
    // 使用 reset 函数传递删除器
    p.reset(new int(20), my_deleter);
    return 0;
}
/*
通过构造函数和 reset 函数分别传递了一个自定义删除器 my_deleter,当 shared_ptr 对象释放资源时,my_deleter 函数会被调用,输出一条消息表示正在删除内存。
*/

weak_ptr(弱指针):

一种多线程安全的指针,一般用于需要访问shared_ptr的场景。不能操作资源。
weak_ptr指针是一种用于解决 shared_ptr 循环引用问题的智能指针,它不能直接使用对象,必须转化为 shared_ptr 对象后进行使用。
它指向由shared_ptr控制的对象,不会增加引用计数,也不会阻止被指向对象的销毁,但它本身不控制该对象。当对象被销毁后,weak_ptr会自动失效。

使用weak_ptr时需要注意以下几点:

  1. 避免直接使用 weak_ptr 指针,可以通过lock函数获取对应的 shared_ptr 对象,再进行操作。
  2. 不要通过 weak_ptr 指针访问对象的成员变量或成员函数,因为对象可能已经被销毁,这样会产生未定义行为。
  3. 如果使用了 shared_ptr 智能指针,则需要小心使用 weak_ptr,因为在 shared_ptr释放底层资源之前,使用 weak_ptr指针可能会导致悬空指针。
  4. 在程序中,尽量减少使用 weak_ptr,只有在必要的场景下才使用,可以避免引发过多的线程安全问题。

unique_ptr(独占指针):

一种独享所有权的指针;拥有“独占”这一特性,即在指针对象的生命周期内,它是指向唯一的对象的,其他的独占指针或普通指针都不能指向这个对象。
它不允许其他的智能指针共享其内部的指针,可以通过它的构造函数初始化一个独占智能指针对象,但是不允许通过赋值将一个unique_ptr赋值给另一个unique_ptr。
当unique_ptr指针被销毁时,它所管理的对象也会随之被销毁,从而保证了对象的唯一性。unique_ptr可以通过移动语义来实现指针的所有权的转让,即将一个unique_ptr的所有权转移给另一个unique_ptr对象。
使用unique_ptr要注意的是不要将同一对象交给不同的unique_ptr对象控制,避免重复delete的问题。
使用 unique_ptr 可以防止多个指针同时使用同一块内存,从而避免内存泄漏的问题。

使用unique_ptr时需要注意以下几点:

  1. unique_ptr是独占式智能指针,即一个unique_ptr拥有指向的对象的所有权,不能被多个指针共享,不能进行复制,只能进行移动操作。
  2. 当unique_ptr被销毁时,它会自动释放指向对象的内存,无需手动释放,从而避免了内存泄漏的问题。
  3. unique_ptr支持自定义释放器,可以通过lambda表达式或自定义函数来实现。
  4. 在使用unique_ptr时,应该避免创建一个指向同一对象的多个unique_ptr,这可能导致不可预期的行为或者程序崩溃。
  5. 可以使用std::move将unique_ptr转移所有权,从而实现指针的所有权转移。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值