一个非空的std::unique_ptr
总是拥有其所涉到的资源;std::unique_ptr
不允许复制,因为如果复制了一个std::unique_ptr
,就会得到两个指涉到同一资源的std::unique_ptr
;
假设我们有一个以Investment为基类的投资类型的继承体系:
class Investment {...};
class Stock: public Iverstment {...};
class Bond: public Iverstment {...};
class RealEstate: public Iverstment {...};
这种继承体系的工厂函数通常会在堆上分配一个对象并且返回一个指涉到它的指针,并当不再需要该对象时,由调用者负责删除之。Investment继承体系的工厂函数如下在:
template<typename... Ts> // 返回std::unique_ptr指涉到根据指定实参创建的对象
std::unique_ptr<Investment> makeInvestment()
调用者可以在单个作用域内像这样来使用返回的std::unique_ptr
:
{
auto pInvestment = makeInvestment(arguments); // pInvestment的类型是std::unique_ptr<Investment>
// *pInvestment在此析构
}
如果由makeInvestment
创建的对象不应该直接删除,而是应该写入一条日志,,那么makeInvestment
可以像下面一样实现:
auto delInvmt = [](Investment *pInvestment) // 一个作为自定义析构器的lambda表达式
{
makeLogEntry(pInvestment);
delete pInvestment;
}
template<typename... Ts> // 改进的返回类型
std::unique_ptr<Investment, decltype()>
makeInvestment(Ts&&... params)
{
std::unique_ptr<Investment, decltype(delInvmt)> pInv(nullptr, delInvmt);
if (/*应该创建一个Stock类型的对象*/) {
pInv.reset(new Stock(std::forward<ts>(params)...));
}
return pInv;
}
-
当使用自定义析构器时,其类型必须制定为
std::unique_ptr
的第二个实参类型。本例中为delInmt
-
将一个裸指针(如new运算符的结果)赋给
std::unique_ptr
的尝试,不会通过编译,因为这会形成裸指针到智能指针的隐式类型转换。 -
自定义析构接受一个类型为
Investment *
的形参,不管在makeInvestment
内实际创建的对象类型是什么,它终究会在lambda
表达式中作为一个Investmnet*
对象被删除。这意味着我们会通过一个基类指针来删除一个派生类对象。为此,基类Investment
必须具备一个析构函数:class Investment { public: //... virtual ~Investment(); };