[c++11]unique_ptr

参考:How to: Create and Use unique_ptr Instances

规范

每个unique_ptr对象都是独立的,无法共享其保存的原始指针,这样能够简化程序逻辑的复杂度。其遵循以下规范:

  1. 它不能复制到另一个unique_ptr对象,或者传递值到函数,或者任何需要复制操作的C++标准库算法
  2. unique_ptr对象保存的指针可以被移动,即内存资源的所有权可以转移到另一个unique_ptr对象,原来的对象就不再拥有

下图演示了两个unique_ptr对象之间的资源转移

unique_ptr实例添加到C++标准库容器是有效的,因为unique_ptr的移动构造器(move constructor)消除了复制操作的需要

成员函数

参考:

std::unique_ptr

unique_ptr Class

unique_ptr常用的成员函数包括:

  • get:返回存储指针,如果为空返回nullptr
  • release:释放存储指针的所有权。返回存储指针且在对象中使用nullptr代替
  • reset:删除当前对象管理的内存资源,并在对象中用nullptr代替存储指针
  • swap:交换两个unique_ptr对象保存的指针
  • operator bool:当前unique_ptr对象是否为空。等价于get() != nullptr

示例1

struct S {
    S(char a, int b) : a(a), b(b) {}

    char a;
    int b;
};

/**
 * @param ptr : lvalue引用方式
 */
void print(const struct S &ptr) {
    cout << ptr.a << " " << ptr.b << endl;
}

int main(int argc, char *argv[]) {
    std::unique_ptr<struct S> uptr(new struct S('c', 3));
    std::unique_ptr<struct S> uptr2(new struct S('d', 4));

    // 打印
    print(*uptr);
    print(*uptr2);

    // 转换信息
    uptr.swap(uptr2);

    // 调用原始指针打印
    struct S *ptr = uptr.get();
    struct S *ptr2 = uptr2.get();
    print(*ptr);
    print(*ptr2);

    // 重置智能指针
    uptr.reset();
    if (!uptr) {
        cout << "ptr is null" << endl;
    }

    // 释放智能指针
    ptr2 = uptr2.release();
    if (!uptr2) {
        cout << "ptr2 is null" << endl;
        print(*ptr2);
        delete (ptr2);
    }
}

结果:

c 3
d 4
d 4
c 3
ptr is null
ptr2 is null
c 3

辅助函数

c++11提供了以下函数来进行unique_ptr的操作

  1. std::make_unique:使用make_unique辅助函数创建unique_ptr对象

  2. std::move:移动一个unique_ptr保存的指针到另一个空的unique_ptr

示例2

struct S {
    S() : a(0), b(0) {}

    S(char a, int b) : a(a), b(b) {}

    char a;
    int b;
};

/**
 * @param ptr : lvalue引用方式
 */
void print(const struct S &ptr) {
    cout << ptr.a << " " << ptr.b << endl;
}

bool isNull(const struct S *ptr) {
    return ptr == nullptr;
}

int main(int argc, char *argv[]) {
    auto uptr = std::make_unique<struct S>('a', 2);
    std::unique_ptr<struct S> uptr2;

    // 打印
    print(*uptr);
    // 转移指针
    uptr2 = std::move(uptr);
    print(*uptr2);
    // 判空
    cout << isNull(uptr.get()) << endl;
    cout << isNull(uptr2.get()) << endl;

    // 创建数组,使用make_unique没有进行初始化
    auto arr = std::make_unique<struct S[]>(5);
    // 初始化
    for (int i = 0; i < 5; i++) {
        arr[i].a = i + '0';
        arr[i].b = i;

        print(arr[i]);
    }
}