参考链接
- std::unique_ptr
介绍
- 定义位于头文件<memory>
- std::unique_ptr 是通过指针占有并管理另一对象,并在 unique_ptr 离开作用域时释放该对象的智能指针。 在下列两者之一发生时用关联的删除器释放对象:1,销毁了管理的 unique_ptr 对象;2, 通过 operator= 或 reset() 赋值另一指针给管理的 unique_ptr 对象。
- 通过调用 get_deleter()(ptr) ,用潜在为用户提供的删除器释放对象。默认删除器用 delete 运算符,它销毁对象并解分配内存。
- unique_ptr 亦可以不占有对象,该情况下称它为空 (empty)。 std::unique_ptr 有两个版本: 1) 管理单个对象(例如以 new 分配) 2) 管理动态分配的对象数组(例如以 new[] 分配)
- 类满足可移动构造 (MoveConstructible) 和可移动赋值 (MoveAssignable) 的要求,但不满足可复制构造 (CopyConstructible) 或可复制赋值 (CopyAssignable) 的要求。
- 只有非 const 的
unique_ptr
能转移被管理对象的所有权给另一unique_ptr
。若对象的生存期为 const std::unique_ptr 所管理,则它被限定在创建指针的作用域中。 std::unique_ptr
常用于管理对象的生存期,包含:- 通过正常退出和经由异常退出两者上的受保证删除,提供异常安全,给处理拥有动态生存期的对象的类和函数
- 传递独占的拥有动态生存期的对象的所有权到函数
- 从函数获得独占的拥有动态生存期对象的所有权
- 作为具移动容器的元素类型,例如保有指向动态分配对象的指针的 std::vector (例如,若想要多态行为)
std::unique_ptr
可为不完整类型T
构造,例如用于改善用作 pImpl 手法中柄的用途。若使用默认删除器,则T
必须在代码中调用删除器点处完整,这发生于析构函数、移动赋值运算符和std::unique_ptr
的reset
成员函数中。(相反地, std::shared_ptr 不能从指向不完整类型的裸指针构造,但可于T
不完整处销毁)。注意若T
是类模板特化,则以unique_ptr
为运算数的使用,如 !p ,因 ADL 而要求T
的形参完整。- 若
T
是某基类B
的派生类,则 std::unique_ptr<T> 可隐式转换为 std::unique_ptr<B>。产生的 std::unique_ptr<B> 的默认删除器将使用B
的 operator delete ,这导致未定义行为,除非B
的析构函数为虚。注意 std::shared_ptr 表现有别: std::shared_ptr<B> 将使用类型T
的 operator delete ,而且即使B
的析构函数非虚,也会正确删除被占有对象。 - 不同于 std::shared_ptr ,
std::unique_ptr
可通过任何满足可空指针 (NullablePointer) 的定制柄类型管理对象。例如,这允许管理位于共享内存,但提供定义typedef boost::offset_ptr pointer;
或其他缀饰指针的Deleter
的对象。
参考代码
#include <iostream>
#include <vector>
#include <memory>
#include <cstdio>
#include <fstream>
#include <cassert>
#include <functional>struct B {virtual void bar() { std::cout << "B::bar\n"; }virtual ~B() = default;
};
struct D : B
{D() { std::cout << "D::D\n"; }~D() { std::cout << "D::~D\n"; }void bar() override { std::cout << "D::bar\n"; }
};// 消费 unique_ptr 的函数能以值或以右值引用接收它
std::unique_ptr<D> pass_through(std::unique_ptr<D> p)
{p->bar();return p;
}void close_file(std::FILE* fp) { std::fclose(fp); }int main()
{std::cout << "unique ownership semantics demo\n";{auto p = std::make_unique<D>(); // p 是占有 D 的 unique_ptrauto q = pass_through(std::move(p)); assert(!p); // 现在 p 不占有任何内容并保有空指针q->bar(); // 而 q 占有 D 对象} // ~D 调用于此std::cout << "Runtime polymorphism demo\n";{std::unique_ptr<B> p = std::make_unique<D>(); // p 是占有 D 的 unique_ptr// 作为指向基类的指针p->bar(); // 虚派发std::vector<std::unique_ptr<B>> v; // unique_ptr 能存储于容器v.push_back(std::make_unique<D>());v.push_back(std::move(p));v.emplace_back(new D);for(auto& p: v) p->bar(); // 虚派发} // ~D called 3 timesstd::cout << "Custom deleter demo\n";std::ofstream("demo.txt") << 'x'; // 准备要读的文件{std::unique_ptr<std::FILE, void (*)(std::FILE*) > fp(std::fopen("demo.txt", "r"),close_file);if(fp) // fopen 可以打开失败;该情况下 fp 保有空指针std::cout << (char)std::fgetc(fp.get()) << '\n';} // fclose() 调用于此,但仅若 FILE* 不是空指针// (即 fopen 成功)std::cout << "Custom lambda-expression deleter demo\n";{std::unique_ptr<D, std::function<void(D*)>> p(new D, [](D* ptr){std::cout << "destroying from a custom deleter...\n";delete ptr;}); // p 占有 Dp->bar();} // 调用上述 lambda 并销毁 Dstd::cout << "Array form of unique_ptr demo\n";{std::unique_ptr<D[]> p{new D[3]};} // 调用 ~D 3 次
}