智能指针(四) unique_ptr
文章目录
unique_ptr 的初始化
- unique_ptr的初始化(和shared_ptr的初始化相同)
// todo 使用 new int
void func()
{
unique_ptr<int> pi;
if (pi == nullptr)
{
cout << "pi is null" << endl;
}
unique_ptr<int> pi2(new int);
if (pi2)
{
cout << "pi2 is 初始化ed" << endl;
}
}
// todo 使用 make_unique
void func2()
{
unique_ptr<int> pi = make_unique<int>(100);
auto p2 = make_unique<int>(100);
if (pi && p2)
{
cout << "pi and p2 is 初始化ed" << endl;
}
}
unique_ptr不支持的操作
- 独占式指针,该智能指针不支持拷贝动作(定义时初始化)
void func()
{
auto i = make_unique<int>(100);
// auto i2(i); // INFO unique_ptr是独占式指针,该智能指针不支持拷贝动作(定义时初始化)
// unique_ptr<int> i2(i);
// unique_ptr<int> i3 =i ; // INFO 智能指针不支持 赋值动作
}
移动语义
void func()
{
unique_ptr<int> i = make_unique<int>(100);
// auto i2=(i);//不允许
auto i2 = std::move(i); // todo 可以转交 控制权
if (nullptr != i2 && nullptr == i)
{
cout << "i指针置空,i2指向i 原来所指向对象" << std::endl;
}
}
release()
-
release() 放对指针的控制权(切断了智能指针和其所指向的对象之间的联系)
-
返回裸指针,将该智能指针置空。返回的这个裸指针我们可以手工delete来释放,
-
也可以用来初始化另外一个智能指针(shared_ptr的get则不可以),
-
release()并不释放内存,仅仅只是将std::unique_ptr中的数据指针置空并抛出数据指针;
void func()
{
unique_ptr<int> ui = make_unique<int>(100);
// 初始化 另一个 智能指针
auto i = ui.release();
if (nullptr != i && nullptr == ui)
{
cout << "ui指针置空,i指向ui 原来所指向对象" << std::endl;
}
}
void func2()
{
unique_ptr<int> ui = make_unique<int>(100);
int *i = ui.release();
delete i; // 返回的 裸指针可以主动delete
if (nullptr == i && nullptr == ui)
{
cout << "ui 和 i 指针 指向空" << std::endl;
}
}
reset()
不带参数
- reset()不带参数情况:释放智能指针所指向的对象,并将智能指针置空。会释放内存
void func()
{
unique_ptr<string> ps1(new string("I Love Chinal !"));
ps1.reset();
if (ps1 = nullptr)
{
cout << "psl被置空" << endl;
}
}
带参数
- 带参数的情况,释放智能指针所指向的对象,并让该智能指针指向新对象
void func2()
{
unique_ptr<string> ps1(new string("I Love Chinal !"));
unique_ptr<string> ps2(new string("I Love Chinal too!"));
cout << "*ps2:: " << *ps2 << endl;
ps1.reset(ps2.release()); // todo 释放了 ps2 指针,并让 ps1 指向 ps2 原先指向的内存
cout << "*ps1:: " << *ps1 << endl;
}
release和 reset 源码比较
另外在std::unique_ptr中有两个成员函数,比较容易混淆,即
pointer release() noexcept {
return _STD exchange(_Mypair._Myval2, nullptr);
}
void reset(pointer _Ptr = nullptr) noexcept {
pointer _Old = _STD exchange(_Mypair._Myval2, _Ptr);
if (_Old) {
_Mypair._Get_first()(_Old);
}
}
从上面的源码中,可以看出,release()并不释放内存,仅仅只是将std::unique_ptr中的数据指针置空并抛出数据指针;而reset(pointer _Ptr = nullptr)会调用析构函数,释放内存。
nullptr
-
nullptr() 释放智能带针所指向的对象,并将智能指针置空*
// 不演示
指向一个数组
void func()
{
unique_ptr<int[]> ps1(new int[10]); // todo 数组这里要跟上[]
for (auto i = 0; i < 10; i++)
{
ps1[i] = i;
}
for (auto i = 0; i < 10; i++)
{
cout << "ps1[" << i << "]" << ps1[i] << endl;
}
}
swap()
-
交换智能指针指向的对象(和shared_ptr相同)
// 不演示
unique_ptr 转换为 shared_ptr
- 如果unique]ptr为右值,就可以将它赋值给shared_ptr
- 因为shared ptr包含一个显式构造函数,可用于将右值unqiue_ptr转换为shared ptr
void func()
{
unique_ptr<int> ui = make_unique<int>(100);
shared_ptr<int> si = (std::move(ui));
cout << "si.get():: " << *si << endl;
}
shared_pre 注意点
unique_ptr 支持拷贝
- 虽然unique ptr智能指针不能拷贝,但是,当这个unique_ptr将要被销毁,是可以拷贝的。最常见用法就是从函数返回
namespace detail
{
unique_ptr<int> func(int nums)
{
return std::unique_ptr<int>(new int(nums));
}
}
auto i = detail::func(150);
cout << "i: " << *i << endl;
指定删除器(和shared_ptr不同)
- 格式:unique_ptr<指向的对象类型,删除器函数类型>智能指针变量名:
void mydelter(string *pdel)
{
cout << "mydelter is called" << endl;
delete pdel;
pdel = nullptr;
};
void func()
{
using T = void (*)(string *);
// unique_ptr<string> ui (new string("mydelter")); //调用默认删除器
unique_ptr<string, T> ui(new string("mydelter"), mydelter);
}
删除器决定对象类型
作为容器元素存储在容器中
namespace detail3
{
void mydelter(string *pdel)
{
cout << "detail3::mydelter is called" << endl;
delete pdel;
pdel = nullptr;
};
int mydelter2(string *pdel)
{
cout << "detail3::mydelter2 is called" << endl;
delete pdel;
pdel = nullptr;
return 0;
};
void func()
{
using T = void (*)(string *);
using T2 = int (*)(string *);
unique_ptr<string> ui1(new string("mydelter")); // 调用默认删除器
unique_ptr<string, T> ui2(new string("mydelter"), mydelter);
unique_ptr<string, T2> ui3(new string("mydelter"), mydelter2);
vector<unique_ptr<string>> vs;
vs.push_back(std::move(ui1));
// vs.push_back(ui2); //error
// vs.push_back(ui3); //error
vector<unique_ptr<string, T>> vsT; // 自定义删除器的必须标明 自定义删除器函数类型
vsT.push_back(std::move(ui2));
// vsT.push_back(std::move(ui3)); // 删除器类型不同, void mydelter(string *pdel)和 int mydelter2(string *pdel),是不同对象,所以不能放入容器中
}
}
unique_ptr需要明确知道类型的析构函数
namespace detail4
{
class TC; // 不提供析构函数
void func()
{
// unique_ptr<TC> up; // error: invalid application of 'sizeof' to incomplete type 'detail4::TC'
shared_ptr<TC> tc; // shared_ptr可以正常运行
}
}
参见 <shared_ptr和unique_ptr深入探秘>
需要明确知道类型的析构函数*
namespace detail4
{
class TC; // 不提供析构函数
void func()
{
// unique_ptr<TC> up; // error: invalid application of 'sizeof' to incomplete type 'detail4::TC'
shared_ptr<TC> tc; // shared_ptr可以正常运行
}
}
参见 <shared_ptr和unique_ptr深入探秘>