Mr.*_*C64 7 c++ smart-pointers resource-management unique-ptr c++11
什么是C++ 11的一些std::unique_ptr用途和陷阱?
我std::unique_ptr还可以使用它来存储动态分配的数组吗?
我std::unique_ptr可以使用自定义删除机制使用资源吗?
Mr.*_*C64 18
让我们使用Q&A格式组织一些用途和陷阱.
Q1:我想在我班级里面存放一个指向班级的指针.
我不希望"容器"类是可复制的; 是实例的唯一所有者.
我知道拥有原始指针是一件坏事,潜在的"泄漏"来源(而不是观察原始指针).我可以为此目的使用什么智能指针?ComponentXXXComponent
A1: C++ 11 std::unique_ptr肯定是个不错的选择.
在独特(非共享)所有权的情况下,它没有问题,并且没有开销std::shared_ptr.
它是以前的C++ 98/03的绝佳替代品boost::scoped_ptr.
实际上,另外,std::unique_ptr还提供了移动语义.
因此,如果类X包含unique_ptr<Component>数据成员(和其他可移动数据成员),则整个类X将自动移动.
示例用法如下所示:
#include <memory> // for std::unique_ptr
class X
{
std::unique_ptr<Component> m_pComponent;
....
public:
X()
: m_pComponent( new Component() )
{
....
}
}
Run Code Online (Sandbox Code Playgroud)
(当然,作为智能指针,不需要在包含类的析构函数中显式删除它.)
Q2:太棒了!不需要显式的析构函数,没有std::shared_ptr开销(典型的C++哲学:"我们不为我们不使用的东西买单"),移动已经实现的语义机制!
但是,我有一个问题:我的类Component有一个构造函数重载,它需要在创建Component实例之前在构造函数代码中计算一些参数.我尝试operator=在构造函数中使用普通的assigment来分配新创建Component的unique_ptr,但是我收到了一条错误消息:
X::X()
{
....
const int param = CalculateCoolParameter();
// This assignment fails:
m_pComponent = new Component(param); // <---- Error pointing to '=' here
^--- error
}
Run Code Online (Sandbox Code Playgroud)
A2:好的,可能你曾经期望operator=过载释放先前拥有的指针(如果有的话)并分配给新创建的指针.
不幸的是,没有这样的超负荷.
但是,std::unique_ptr::reset()方法会做!
m_pComponent.reset( new Component(param) );
Run Code Online (Sandbox Code Playgroud)
Q3:嘿!这unique_ptr真的很酷!我喜欢这样一个事实:它很聪明,它可以自动移动,并且不会带来开销.
所以,我想用它来存储一个动态分配的一些常量大小的数组(在运行时计算)而不是使用std::vector(在这部分代码中我受到高度约束,我不想为此付出代价std:vector开销,因为我不想要所有std::vector动态调整大小的功能,深层复制等).
我试过这样的事情:
const size_t count = GetComponentsCount();
unique_ptr<Component> components( new Component[count] );
Run Code Online (Sandbox Code Playgroud)
编译很好,但我注意到~Component析构函数只被调用一次,而不是我期望count析构函数调用!这里出了什么问题?
A3:问题在于,使用上述语法,std::unique_ptr用于delete释放分配的对象.但是由于这些是使用分配的new[],所以正确的清理调用是delete[](不是delete没有括号的简单).
要解决此问题并指示unique_ptr正确使用delete[]以释放资源,必须使用以下语法:
unique_ptr<Component[]> components( new Components[count] );
// ^^
//
// Note brackets "[]" after the first occurrence of "Component"
// in unique_ptr template argument.
//
Run Code Online (Sandbox Code Playgroud)
Q4:太棒了!但是,我unique_ptr也可以在不使用普通C++ delete(或delete[])执行资源释放代码的情况下使用,而是使用一些自定义清理功能,例如fclose()C <stdio.h>文件(打开fopen())或CloseHandle()Win32文件HANDLE(使用创建CreateFile())?
A4:这绝对是可能的:你可以指定一个自定义删除器std::unique_ptr.
例如:
//
// Custom deleter function for FILE*: fclose().
//
std::unique_ptr<FILE, // <-- the wrapped raw pointer type: FILE*
int(*)(FILE*)> // <-- the custom deleter type: fclose() prototype
myFile( fopen("myfile", "rb"), // <-- resource (FILE*) is returned by fopen()
fclose ); // <-- the deleter function: fclose()
//
// Custom deleter functor for Win32 HANDLE: calls CloseHandle().
//
struct CloseHandleDeleter
{
// The following pointer typedef is required, since
// the raw resource is HANDLE (not HANDLE*).
typedef HANDLE pointer;
// Custom deleter: calls CloseHandle().
void operator()(HANDLE handle) const
{
CloseHandle(handle);
}
};
std::unique_ptr<HANDLE, CloseHandleDeleter> myFile( CreateFile(....) );
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3851 次 |
| 最近记录: |