九、 通用工具 ----smart Pointer(智能指针)---unique_ptr

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的所有操作

unique_ptr的所有操作

unique_ptr的所有操作

3.2.1 unique_ptr的赋值
  1. 使用release()和reset()方法
  2. 使用move赋值
  3. 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当做成员

  1. 在类中使用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))
    {}
//析构器不重要,默认析构就行了
};
  1. 析构函数只有当构造函数执行成功时,才有可能被调用;
  2. 当两个new执行中,一个成功,一个失败,导致异常,在内置指针的版本中,发生资源泄露;使用unique_ptr略写析构函数,unique_ptr会释放资源;

3.4 对付array

  1. 默认的unique_ptr如果失去拥有权,对象被调用delete;
  2. array 需要调用delete[]
  3. c++ri标准库提供了特殊版本的unique_ptr处理数组
unique_ptr<string> up(new string[10]);  //error
unique_ptr<string[]> up(new string[10]);  //ok

说明:
特化版本的不同:

  1. 特化版本不能使用操作符 * 和 —>;
  2. 只能使用操作符 [];
  3. 这个版本不接受派生类型的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()传递实参;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值