用std::unique_ptr管理所有权唯一的资源¶
使用智能指针时一般首选 std::unique_ptr,默认情况下它和原始指针尺寸相同。
std::unique_ptr 对资源拥有唯一所有权,因此它是 move-obly 类型,不允许拷贝。它常用作工厂函数的返回类型,这样工厂函数生成的对象在需要销毁时会被自动析构,而不需要手动析构
class A {};
std::unique_ptr<A> makeA()
{
return std::unique_ptr<A>(new A);
}
auto p = makeA();
std::unique_ptr 的析构默认通过 delete 内部的原始指针完成,但也可以自定义删除器,删除器需要一个std::unique_ptr 内部指针类型的参数。
class A {};
auto f = [](A* p) { std::cout << "destroy\n"; delete p; };
std::unique_ptr<A, decltype(f)> makeA()
{
std::unique_ptr<A, decltype(f)> p(new A, f);
return p;
}
使用 C++14 的 auto 返回类型,可以将删除器的 lambda 定义在工厂函数内,封装性更好一些。
class A {};
auto makeA()
{
auto f = [](A* p) { std::cout << "destroy\n"; delete p; };
std::unique_ptr<A, decltype(f)> p(new A, f);
return p;
}
可以进一步扩展成支持继承体系的工厂函数:
class A {
public:
virtual ~A() {} //@ 删除器对任何对象调用的是基类的析构函数,因此必须声明为虚函数
};
class B : public A {}; //@ 基类的析构函数为虚函数,则派生类的析构函数默认为虚函数
class C : public A {};
class D : public A {};
auto makeA(int i)
{
auto f = [](A* p) { std::cout << "destroy\n"; delete p; };
std::unique_ptr<A, decltype(f)> p(nullptr, f);
if (i == 1) p.reset(new B);
else if (i == 2) p.reset(new C);
else p.reset(new D);
return p;
}
默认情况下,std::unique_ptr 和原始指针尺寸相同,如果自定义删除器则 std::unique_ptr 会加上删除器的尺寸。一般无状态的函数对象(如无捕获的 lambda)不会浪费任何内存,作为删除器可以节约空间。
class A {};
auto f = [](A* p) { delete p; };
void g(A* p) { delete p; }
struct X {
void operator()(A* p) const { delete p; }
};
std::unique_ptr<A> p1(new A);
std::unique_ptr<A, decltype(f)> p2(new A, f);
std::unique_ptr<A, decltype(g)*> p3(new A, g);
std::unique_ptr<A, decltype(X())> p4(new A, X());
//@ 机器为64位
std::cout << sizeof(p1) //@ 8:默认尺寸,即一个原始指针的尺寸
<< sizeof(p2) //@ 8:无捕获lambda不会浪费尺寸
<< sizeof(p3) //@ 16:函数指针占一个原始指针尺寸
<< sizeof(p4); //@ 8:无状态的函数对象。但如果X中存储了状态(如数据成员、虚函数)就会增加尺寸
std::unique_ptr 作为返回类型的另一个方便之处是,可以转为 std::shared_ptr 。
//@ std::make_unique 的返回类型是std::unique_ptr
std::shared_ptr<int> p = std::make_unique<int>(42); //@ OK
std::unique_ptr 针对数组提供了一个特化版本,此版本提供 operator[],但不提供单元素版本的 [operator*]和 [operator->],这样对其指向的对象就不存在二义性。
std::unique_ptr<int[]> p(new int[3]{11, 22, 33});
for(int i = 0; i < 3; ++i) std::cout << p[i];