C++之智能指针 unique_ptr 和 shared_ptr

文章目录


C++指针没有只能算是一个小垃圾回收站,因为java,go都有一个专门的垃圾回收机制,无用指针会直接回收,C++只能通过析构函数等自己写,释放无用指针,累。

智能指针就是代替你来干这些“脏活累活”的。它完全实践了 RAII,包装了裸指针,而且因为重载了 * 和 -> 操作符,用起来和原始指针一模一样。

不仅如此,它还综合考虑了很多现实的应用场景,能够自动适应各种复杂的情况,防止误用指针导致的隐患,非常“聪明”,所以被称为“智能指针”。

常用的有两种智能指针,分别是 unique_ptr 和 shared_ptr,下面我就来分别介绍一下。

一、unique_ptr

unique_ptr 是最简单、最容易使用的一个智能指针,在声明的时候必须用模板参数指定类型:


unique_ptr<int> ptr1(new int(10));      // int智能指针
assert(*ptr1 == 10);                     // 可以使用*取内容
assert(ptr1 != nullptr);                // 可以判断是否为空指针

unique_ptr<string> ptr2(new string("hello"));  // string智能指针
assert(*ptr2 == "hello");                // 可以使用*取内容
assert(ptr2->size() == 5);               // 可以使用->调用成员函数

你需要注意的是,unique_ptr 虽然名字叫指针,用起来也很像,但它实际上并不是指针,而是一个对象。所以,不要企图对它调用 delete,它会自动管理初始化时的指针,在离开作用域时析构释放内存。另外,它也没有定义加减运算,不能随意移动指针地址,这就完全避免了指针越界等危险操作,可以让代码更安全:


ptr1++;                        // 导致编译错误
ptr2 += 2;                     // 导致编译错误

除了调用 delete、加减运算,初学智能指针还有一个容易犯的错误是把它当成普通对象来用,不初始化,而是声明后直接使用:


unique_ptr<int> ptr3;                // 未初始化智能指针
*ptr3 = 42 ;                         // 错误!操作了空指针

未初始化的 unique_ptr 表示空指针,这样就相当于直接操作了空指针,运行时就会产生致命的错误(比如 core dump)。为了避免这种低级错误,你可以调用工厂函数 make_unique(),强制创建智能指针的时候必须初始化。同时还可以利用自动类型推导的 auto,少写一些代码:


auto ptr3 = make_unique<int>(42);               // 工厂函数创建智能指针
assert(ptr3 && *ptr3 == 42);

auto ptr4 = make_unique<string>("god of war");  // 工厂函数创建智能指针
assert(!ptr4->empty());

不过,make_unique() 要求 C++14,好在它的原理比较简单。如果你使用的是 C++11,也可以自己实现一个简化版的 make_unique(),可以参考下面的代码:


template<class T, class... Args>              // 可变参数模板
std::unique_ptr<T>                            // 返回智能指针
my_make_unique(Args&&... args)                // 可变参数模板的入口参数
{
    return std::unique_ptr<T>(                // 构造智能指针
            new T(std::forward<Args>(args)...));    // 完美转发
}

unique_ptr 的所有权使用 unique_ptr 的时候还要特别注意指针的“所有权”问题。正如它的名字,表示指针的所有权是“唯一”的,不允许共享,任何时候只能有一个“人”持有它。

为了实现这个目的,unique_ptr 应用了 C++ 的“转移”(move)语义,同时禁止了拷贝赋值**,所以,在向另一个 unique_ptr 赋值的时候,要特别留意,必须用 std::move() 函数显式地声明所有权转移。**赋值操作之后,指针的所有权就被转走了,原来的 unique_ptr 变成了空指针,新的 unique_ptr 接替了管理权,保证所有权的唯一性:


auto ptr1 = make_unique<int>(42);    // 工厂函数创建智能指针
assert(ptr1 && *ptr1 == 42);         // 此时智能指针有效

auto ptr2 = std::move(ptr1);         // 使用move()转移所有权
assert(!ptr1 && ptr2);               // ptr1变成了空指针
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值