条款18使用std:;unique_ptr管理具备专属所有权的资源:
每当你需要使用智能指针的时候,std::unique_ptr基本是最合适的。可以认为在默认情况下,std::unique_ptr
性能等同于原始指针,而且对于大多数操作(包括解引用),它们执行的指令完全相同。这意味着你甚至可以在内存和时间都比较紧张的情况下使用它。如果原始指针够小够快,那么std::unique_ptr
几乎可以肯定也能满足你的要求。
std::unique_ptr体现了专有所有权语义。一个非空的std::unique_ptr总是拥有其所指向的资源。移动一个std::unique_ptr会将所有权从源指针移动到目标指针(原指针被置空)。拷贝操作是不允许的,因为如果你能拷贝一个std::unique_ptr
,你会得到指向相同内容的两个std::unique_ptr
,每个都认为自己拥有资源,销毁时也会出现重复销毁。因此,std::unique_ptr
只支持移动操作。当std::unique_ptr
销毁时,其指向的资源也执行析构函数。而原始指针需要显式调用delete
来销毁指针指向的资源。
std::unique_ptr
有两种形式,一种用于单个对象(std::unique_ptr<T>
),一种用于数组(std::unique_ptr<T[]>
)。数组的std::unique_ptr
的存在应该不被使用,因为std::array
,std::vector
,std::string
这些更好用的数据容器应该取代原始数组。
unique_ptr特点:
在没有自定义析构器的情况下,可以认为unique_ptr和裸指针大小相同!
但如果有自定义析构器,就不同了。
- 如果自定义析构器是
函数指针
,那么std::unique_ptr
的尺寸一般会增加1到2个字长。 - 如果自定义析构器是
函数对象
,那么std::unique_ptr
的尺寸取决于该函数对象中存储了多少状态。特别指出,无状态的函数对象(例如,无捕获的lambda表达式)不会浪费存储尺寸
意味着,如果自定义表达器,既可以用函数也可以用无捕获的lambda表达式的时候,lambda表达式会是更好的选择。
class Test
{
public:
Test()noexcept
{
}
~Test()noexcept
{
}
};
auto deleter = [](Test* p)
{
if (p)
{
delete p;
}
cout << "自定义删除器调用" << endl;
};
int main()
{
unique_ptr<Test, decltype(deleter)> p{ new Test{},deleter };
cout << sizeof(p) << endl;
return 0;
}
std::unique_ptr
也可以很方便的转换成std::shared_ptr
:
unique_ptr<Test> p{ new Test{}};
shared_ptr<Test> q = make_shared<Test>(p);
要点速记 |
---|
1. std::unique_ptr是小巧的,高速的,只能移动的智能指针,对托管资源实施专属所有权语义。 |
2. 默认的,析构器采用delete实现,也可以指定自定义析构器。但有状态捕获和函数指针的实现方式会增加std::unique_ptr变量的尺寸。 |
3. 将std::unique_ptr转换成std::shared_ptr是很方便的。 |
Comments NOTHING