关注公众号获取更多信息:
std::unique_ptr是C++11标准中用来取代std::auto_ptr的指针容器(在C++11中,auto_ptr被废弃)。它不能与其它unique_ptr类型的指针对象共享所指对象的内存。这种”所有权”仅能够通过标准库的move函数来转移。unique_ptr是一个删除了拷贝构造函数、保留了移动构造函数的指针封装类型。下面的脑图总结了unique_ptr的特性:
1. 一个unique_ptr"拥有"它所指向的对象。与shared_ptr不同,某个时刻只能有一个unique_ptr指向一个给定对象。当unique_ptr被销毁时,它所指向的对象也被销毁。
2. 与shared_ptr不同,在C++11中,没有类似make_shared的标准库函数返回一个unique_ptr。当定义一个unique_ptr时,需要将其绑定到一个new返回的指针上。至于为什么没有make_unique的标准函数库。标准的人说:“忘了”?????不过到了C++14,标准中加入了make_unique的定义。其实如果想用make_unique我们可以实现一个简单版本的:
template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args)
{
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
3. 类似shared_ptr,初始化unique_ptr必须采用直接初始化形式。由于一个unique_ptr拥有它指向的对象,因此unique_ptr不支持普通的拷贝或赋值操作。虽然不能拷贝或赋值unique_ptr,但可以通过调用release或reset将指针的所有权从一个(非const)unique_ptr转移给另一个unique。
不能拷贝unique_ptr的规则有一个例外:我们可以拷贝或赋值一个将要被销毁的unique_ptr (C++ Primer 5th p418)
//从函数返回一个unique_ptr
unique_ptr func1(int a)
{
return unique_ptr<int> (new int(a));
}
//返回一个局部对象的拷贝
unique_ptr func2(int a)
{
unique_ptr<int> up(new int(a));
return up;
}
传unique_ptr参数可以使用引用避免所有权的转移,或者暂时的移交所有权
void func1(unique_ptr<int> &up){
cout<<*up<<endl;
}
unique_ptr<int> func2(unique_ptr<int> up){
cout<<*up<<endl;
return up;
}
//使用up作为参数
unique_ptr<int> up(new int(10));
//传引用,不拷贝,不涉及所有权的转移
func1(up);
//暂时转移所有权,函数结束时返回拷贝,重新收回所有权
up = func2(unique_ptr<int> (up.release()));
//如果不用up重新接受func2的返回值,这块内存就泄漏了
4. 调用release会切断unique_ptr和它原来管理的对象间的联系。release返回的指针通过被用来初始化另一个智能指针或给另一个智能指针赋值。如果不用另一个智能指针来保存release返回的指针,程序就要负责资源的释放。
5. 类似shared_ptr,unique_ptr默认情况下用delete释放它指向的对象。与shared_ptr一样,可以重载一个unique_ptr中默认的删除器。但是,unique_ptr管理删除器的方式与shared_ptr不同。
默认情况下,std::shared_ptr会调用delete来清空内存。当使用new[] 分配内存时,需要调用delete[] 来释放内存,否则会有内存泄露。
可以通过以下代码来自定义释放内存的函数:
template< typename T >
struct array_deleter
{
void operator ()(T const * p)
delete[] p;
}
};
通过以下代码来声明std::shared_ptr指针:
std::shared_ptr<int> sp(new int[10], array_deleter<int>());
此时,shared_ptr可正确的调用delete[]。
在C++11中,可以使用 std::default_delete代替上面自己写的array_deleter:
std::shared_ptr<int> sp(new int[10], std::default_delete<int[]>());
也可以使用一下的lambda表达式来自定义删除函数
std::shared_ptr<int> sp(new int[10], [](int *p) { delete[] p; });
实际上,除非需要共享目标,否则unique_ptr更适合使用数组:
std::unique_ptr<int[]> up(new int[10]); // this will correctly call delete[]
上面代码可以正确的分配空间,但是空间内的值都没有初始化。如果需要默认初始化为0,可以使用下面的代码:
std::unique_ptr<int[]> up(new int[10]()); // this will correctly call delete[] 初始化为0
6. unique_ptr的常用操作
unique_ptr<T> up
空的unique_ptr,可以指向类型为T的对象,默认使用delete来释放内存
unique_ptr<T,D> up(d)
空的unique_ptr同上,接受一个D类型的删除器d,使用删除器d来释放内存
up = nullptr
释放up指向的对象,将up置为空
up.release()
up放弃对它所指对象的控制权,并返回保存的指针,将up置为空,不会释放内存
up.reset(…)
参数可以为 空、内置指针,先将up所指对象释放,然后重置up的值.