C++智能指针之唯一指针(std::unique_ptr)

1 概述

从C++11开始C++语言越来向现代化语言转变。尤其是智能指针的引入,代码中不会直接使用new/delete了。C++11智能指针有三种分别是:shared_ptr,weak_ptr 和unique_ptr 。

2 唯一指针(unique_ptr)

unique_ptr是C++11引入的,用来管理指针,取代C++98中的auto_ptr.其类图如下:

unique_ptr的特性:

  • 不可复制性,体现在拷贝构造函数和拷贝赋值函数是私有的(或delete的)
  • 可移动性,体现在移动构造函数和移动赋值函数。
  • 可交换性,通过swap函数交换两个unique_ptr对象
  • 可重置性,通过rest函数重置管理指针
  • 可释放性,通过release函数释放对指针的管理
  • 可管理多种指针类型,既可以管理new分配指针和数组,也可以管理malloc分配指针,不过需要定制deleter。

2 使用实例

cpp 复制代码
void UniquePtrSuite::dereference_obj_member()
{
    std::unique_ptr<Array> a(new Array(10));
    TEST_ASSERT_EQUALS(10,  a->size())
    
    std::cout << "\na.size=" << a->size() << std::endl;

    std::unique_ptr<Array> b;
    if(b)
        std::cout << "\nb.size=" << b->size() << std::endl;
}

通过重载->操作符,统一指针可以像原始指针一样使用。

3 接口使用

3.1 construct/get

cpp 复制代码
获取管理的指针
void UniquePtrSuite::get()
{
    std::default_delete<int> del;
    std::unique_ptr<int> a;
    std::unique_ptr<int> b(nullptr);
    std::unique_ptr<int> c(new int(10));
    std::unique_ptr<int> d(new int(10), del);
    std::unique_ptr<int> e(new int(10), std::default_delete<int>());
    std::unique_ptr<int> f(std::move(d));

    TEST_ASSERT_EQUALS(true, a.get() == nullptr)
    TEST_ASSERT_EQUALS(true, b.get() == nullptr)
    TEST_ASSERT_EQUALS(true, c.get() != nullptr)
    TEST_ASSERT_EQUALS(true, d.get() == nullptr)
    TEST_ASSERT_EQUALS(true, e.get() != nullptr)
    TEST_ASSERT_EQUALS(true, f.get() != nullptr)
}

3.2 operator bool

可以通过if条件语句判断指针是否不为空

cpp 复制代码
void UniquePtrSuite::check_bool()
{
    std::default_delete<int> del;
    std::unique_ptr<int> a;
    std::unique_ptr<int> b(nullptr);
    std::unique_ptr<int> c(new int(10));
    std::unique_ptr<int> d(new int(10), del);
    std::unique_ptr<int> e(new int(10), std::default_delete<int>());
    std::unique_ptr<int> f(std::move(d));

    TEST_ASSERT_EQUALS(false, (bool)a)
    TEST_ASSERT_EQUALS(false, (bool)b)
    TEST_ASSERT_EQUALS(true,  (bool)c)
    TEST_ASSERT_EQUALS(true,  (bool)c)
    TEST_ASSERT_EQUALS(true,  (bool)e)
    TEST_ASSERT_EQUALS(true,  (bool)f)
}

3.3 operator *

获取指针指向对象和变量

cpp 复制代码
void UniquePtrSuite::dereference_obj()
{
    std::unique_ptr<int> a(new int(10));
    TEST_ASSERT_EQUALS(10,  *a)
    std::unique_ptr<int> b;
    std::cout << "\na=" << *a << std::endl;
    if(b)
        std::cout << "\nb=" << *a << std::endl;
}

3.3 operator ->

该接口只有类是对象情况下使用

cpp 复制代码
void UniquePtrSuite::dereference_obj_member()
{
    std::unique_ptr<Array> a(new Array(10));
    TEST_ASSERT_EQUALS(10,  a->size())
    
    std::cout << "\na.size=" << a->size() << std::endl;

    std::unique_ptr<Array> b;
    if(b)
        std::cout << "\nb.size=" << b->size() << std::endl;
}

3.4 operator =

移动赋值操作

cpp 复制代码
void UniquePtrSuite::assign()
{
    std::unique_ptr<int> a(new int(10));
    std::unique_ptr<int> b(new int(10));
    TEST_ASSERT_EQUALS(true, (bool)a)
    a = nullptr;
    TEST_ASSERT_EQUALS(false, (bool)a)
    //a = b; error
    TEST_ASSERT_EQUALS(true, (bool)b)
    a = std::move(b);
    TEST_ASSERT_EQUALS(true, (bool)a)
    TEST_ASSERT_EQUALS(false, (bool)b)
}

3.5 release

返回并释放指针管理权

cpp 复制代码
void UniquePtrSuite::release()
{
    std::default_delete<int> del;
    std::unique_ptr<int> a;
    std::unique_ptr<int> b(nullptr);
    std::unique_ptr<int> c(new int(10));
    std::unique_ptr<int> d(new int(10), del);
    std::unique_ptr<int> e(new int(10), std::default_delete<int>());
    std::unique_ptr<int> f(std::move(d));
    int* a_ptr = a.release();
    int* b_ptr = b.release();
    int* c_ptr = c.release();
    int* d_ptr = d.release();
    int* e_ptr = e.release();
    int* f_ptr = f.release();

    TEST_ASSERT_EQUALS(false, (bool)a)
    TEST_ASSERT_EQUALS(false, (bool)b)
    TEST_ASSERT_EQUALS(false, (bool)c)
    TEST_ASSERT_EQUALS(false, (bool)c)
    TEST_ASSERT_EQUALS(false, (bool)e)
    TEST_ASSERT_EQUALS(false, (bool)f)

    TEST_ASSERT_EQUALS(true, a_ptr == nullptr)
    TEST_ASSERT_EQUALS(true, b_ptr == nullptr)
    TEST_ASSERT_EQUALS(true, c_ptr != nullptr)
    TEST_ASSERT_EQUALS(true, d_ptr == nullptr)
    TEST_ASSERT_EQUALS(true, e_ptr != nullptr)
    TEST_ASSERT_EQUALS(true, f_ptr != nullptr)
    delete a_ptr;
    delete b_ptr;
    delete c_ptr;
    delete d_ptr;
    delete e_ptr;
    delete f_ptr;
}

3.6 reset

重置指针,delete管理的指针,并管理新传入指针(如果有的话)

cpp 复制代码
void UniquePtrSuite::reset()
{
    std::unique_ptr<int> a;
    TEST_ASSERT_EQUALS(false, (bool)a)
    a.reset();
    TEST_ASSERT_EQUALS(false, (bool)a)
    a.reset(new int(10));
    TEST_ASSERT_EQUALS(true, (bool)a)
    a.reset();
    TEST_ASSERT_EQUALS(false, (bool)a)
}

3.7 swap

交换两个指针

cpp 复制代码
void UniquePtrSuite::swap()
{
    std::unique_ptr<int> a;
    std::unique_ptr<int> b(new int(10));
    std::unique_ptr<int> c(new int(50));
    std::unique_ptr<int> d(new int(100));
    TEST_ASSERT_EQUALS(false, (bool)a)
    a.swap(b);
    TEST_ASSERT_EQUALS(true, (bool)a)
    TEST_ASSERT_EQUALS(false, (bool)b)

    TEST_ASSERT_EQUALS(50, *c)
    TEST_ASSERT_EQUALS(100, *d)
    c.swap(d);
    TEST_ASSERT_EQUALS(100, *c)
    TEST_ASSERT_EQUALS(50, *d)
}

3.8 get_deleter

获取指针deleter

cpp 复制代码
class MyDeleter
{
    int count_;
public:
    MyDeleter() : count_(0) {}
    int count() { return count_; }

    template<class T>
    void operator()(T* p)
    {
        std::cout << "\n[deleted #" << ++count_ << "]\n";
        delete p;
    }
};

void UniquePtrSuite::get_deleter()
{
    MyDeleter del;
    std::unique_ptr<int, MyDeleter> a(new int);
    std::unique_ptr<int, MyDeleter> b(new int, a.get_deleter());
    std::unique_ptr<int, MyDeleter&> c(new int, del);
    std::unique_ptr<int, MyDeleter&> d(new int, c.get_deleter());

    auto & a_deleter = a.get_deleter();
    auto & b_deleter = b.get_deleter();
    auto & c_deleter = c.get_deleter();
    auto & d_deleter = d.get_deleter();

    a.reset();
    TEST_ASSERT_EQUALS(1, a_deleter.count())
    b.reset();
    TEST_ASSERT_EQUALS(1, b_deleter.count())
    c.reset();
    TEST_ASSERT_EQUALS(1, c_deleter.count())
    TEST_ASSERT_EQUALS(1, del.count())
    d.reset();
    TEST_ASSERT_EQUALS(2, d_deleter.count())
    TEST_ASSERT_EQUALS(2, del.count())
}

说明:

  • 如果MyDeleter&类型,多个对象可以共享一个deleter

3.9 operator []

该接口只有在类型是数组情况下使用

cpp 复制代码
void UniquePtrSuite::offeset()
{
    std::unique_ptr<int[]> a (new int[5]);
    for(int i = 0; i < 5; i++)
        a.get()[i] = i;

    for(int i = 0; i < 5; i++)
        TEST_ASSERT_EQUALS(i, a[i])

    for(int i = 0; i < 5; i++)
        a[i] = i;

    for(int i = 0; i < 5; i++)
        TEST_ASSERT_EQUALS(i, a[i])
}
相关推荐
Evand J1 小时前
LOS/NLOS环境建模与三维TOA定位,MATLAB仿真程序,可自定义锚点数量和轨迹点长度
开发语言·matlab
LucianaiB1 小时前
探索CSDN博客数据:使用Python爬虫技术
开发语言·爬虫·python
Ronin3051 小时前
11.vector的介绍及模拟实现
开发语言·c++
✿ ༺ ོIT技术༻1 小时前
C++11:新特性&右值引用&移动语义
linux·数据结构·c++
字节高级特工1 小时前
【C++】深入剖析默认成员函数3:拷贝构造函数
c语言·c++
计算机学长大白2 小时前
C中设计不允许继承的类的实现方法是什么?
c语言·开发语言
PieroPc3 小时前
Python 写的 智慧记 进销存 辅助 程序 导入导出 excel 可打印
开发语言·python·excel
2401_857439695 小时前
SSM 架构下 Vue 电脑测评系统:为电脑性能评估赋能
开发语言·php
SoraLuna6 小时前
「Mac畅玩鸿蒙与硬件47」UI互动应用篇24 - 虚拟音乐控制台
开发语言·macos·ui·华为·harmonyos
xlsw_6 小时前
java全栈day20--Web后端实战(Mybatis基础2)
java·开发语言·mybatis