3 class unique_ptr
c++11提供,继承class auto_ptr
1. 独占式拥有
2. unique_ptr被销毁,指向的对象也被销毁;
3.1. unique_ptr的构造函数
//default (1)
constexpr unique_ptr() noexcept;
//from null pointer (2)
constexpr unique_ptr (nullptr_t) noexcept : unique_ptr() {}
//from pointer (3)
explicit unique_ptr (pointer p) noexcept;
//from pointer + lvalue deleter (4)
unique_ptr (pointer p,
typename conditional<is_reference<D>::value,D,const D&> del) noexcept;
//from pointer + rvalue deleter (5)
unique_ptr (pointer p,
typename remove_reference<D>::type&& del) noexcept;
//move (6)
unique_ptr (unique_ptr&& x) noexcept;
//move-cast (7)
template <class U, class E>
unique_ptr (unique_ptr<U,E>&& x) noexcept;
//move from auto_ptr (8)
template <class U>
unique_ptr (auto_ptr<U>&& x) noexcept;
//copy (deleted!) (9)
unique_ptr (const unique_ptr&) = delete;
说明:
1. unique_ptr有以上形式的构造函数
2. 可以使用空指针,内置指针,等构造unique_ptr
3. 但是不能够用unique_ptr拷贝初始化
4. 初始化需要使用直接初始化,不能进行隐式转换
例子:
//直接初始化
unique_ptr<string> s(new string("string"));
unique_ptr<string> s= new string("hello"); //error
unique_ptr<string> u (s);//error,不能使用unique_ptr去初始化另一个
3.2 unique_ptr的所有操作
3.2.1 unique_ptr的赋值
- 使用release()和reset()方法
- 使用move赋值
- swap方法
unique_ptr<int> s; //默认构造函数
unique_ptr<int> p(new int(42));
//赋值,使用release()放弃拥有权,reset()获得拥有权
int* i = p.release();
s.reset(i);
//move
s = std::move(p);//ok
//swap
s.wap(p);//交换
3.2.2 传递unique_ptr参数和返回unqiue_ptr
不能拷贝unique_ptr的规则例外:可以拷贝或赋值一个将要被销毁的unique_ptr
例子:
(1.)unique_ptr作为返回值
//unique_ptr作为返回值
unique_ptr<int> clone(int p){
//从int*创建一个
return unique_ptr<int>(new int(p));
}
//返回一个局部对象的拷贝
unique_ptr<int> clone(int p){
unique_ptr<int> s (new int(p));
return s;
}
//-----------------------------------------
原因: 编译器会自动尝试加上std::move(),来转移所有权;
(2).unique_ptr作为参数
需要使用std::move()建立的unique_ptr以右值的方式作为函数参数;如果函数不在转移所有权,那么对象会在函数结束的时候被deleted;
void test(std::unique_ptr<int> u)
{
//...
}
unique_ptr<int> p(new int(12));
//...
test(move(p)); //p失去拥有权
3.3 unique_ptr当做成员
- 在类中使用unique_ptr可避免资源泄露;如对象初始化异常造成资源泄露,unique_ptr可避免;
例如:
class A{
private:
int * p;
int * f;
public:
A(int a, int b):p(new int(a)),f(new int(b))
{}
~A()
{
delete p;
delete f;
}
};
//unique_ptr
class A{
private:
unique_ptr<int> p;
unique_ptr<int> f;
public:
A(int a, int b):p(new int(a)),f(new int(b))
{}
//析构器不重要,默认析构就行了
};
- 析构函数只有当构造函数执行成功时,才有可能被调用;
- 当两个new执行中,一个成功,一个失败,导致异常,在内置指针的版本中,发生资源泄露;使用unique_ptr略写析构函数,unique_ptr会释放资源;
3.4 对付array
- 默认的unique_ptr如果失去拥有权,对象被调用delete;
- array 需要调用delete[]
- c++ri标准库提供了特殊版本的unique_ptr处理数组
unique_ptr<string> up(new string[10]); //error
unique_ptr<string[]> up(new string[10]); //ok
说明:
特化版本的不同:
- 特化版本不能使用操作符
* 和 —>
; - 只能使用操作符
[]
; - 这个版本不接受派生类型的array作为,不支持不同接口的转换;
例子:
unique_ptr<string[]> up(new string[10]);
cout<<*up<<endl; // error
cout<<up[0]<<endl; //ok
3.5 其他资源的deleter
unique_ptr的构造参数可以传递一个deleter对象作为第二参数,
1. 该类型可以是一个函数引用,或是一个函数指针,或者函数对象;
例如:
//函数对象
class ADeleter
{
public:
void operator()(classA * p)
{
cout<<"call deleter for classA object"<<endl;
delete p;
}
};
//........
unique_ptr<classA,ADleter> up(new classA());
//函数或者lambda ,必须声明deleter的类型为void(*)(T*)或者std::function<void(T*)>,或者使用decltype
auto func = [](int* p){delete p;};
//这两个形式都可以,只要指出了deleter类型,自动调用;
unique_ptr<int,decltype(func) > up(new int(43),func);
unique_ptr<int,decltype(func)> s(new int(42));
3.6 auto_ptr
auto_ptr的危险: 非自觉遗失所有权
例子:
template<typename T>
void bad_print(auto_ptr<T> s)
{
//....
}
//....
auto_ptr<int> p(new int);
*p = 42;
bad_print(p); //p指向对象程序结束后被删除
*p = 18; //运行错误
auto_ptr被当做实参传递,则这个auto_ptr的所有权被移交给了函数形参s,而s在函数结束前释放掉对象,因此发生上面错误;unique_ptr必须显式的指定使用std::move()传递实参;