1、shared_ptr(共享式内存)
普通对象自定义deleter:
错误用法(自定义deleter时不能使用make_shared<>())
std::shared_ptr<std::string> p_str = std::make_shared<std::string>("name",
[](std::string *str) {
std::cout << "delete: " << str << std::endl;
delete str;
});
正确用法
std::shared_ptr<std::string> p_str(new std::string("name"),
[](std::string *str) {
std::cout << "delete: " << *str << std::endl;
delete str;
});
数组对象自定义deleter
std::default_delete只针对单个类对象,因此如果是数组,则需要指定deleter
// 使用自定义deleter
std::shared_ptr<int> p_arr(new int[10],
[](int *arr) {
std::cout << "delete array."<< std::endl;
delete []arr;
});
// 使用缺省deleter
std::shared_ptr<int> p_arr_a(new int[10], std::default_delete<int []>());
weak_ptr
是 shared_ptr的帮手,用来共享对象但不拥有对象,它的use_count返回的是shared_ptr拥有的次数
可以解决类之间互相引用,而导致两者都不会被析构的场景
std::shared_ptr<std::string> p_str_a = std::make_shared<std::string>("nana");
std::weak_ptr<std::string> p_str_w1 = p_str_a;
std::cout << "A expired:" << p_str_w1.expired() << std::endl;
std::cout << "A use_count:" << p_str_w1.use_count() << std::endl;
std::shared_ptr<std::string> p_str_a2 = p_str_a;
std::cout << "A expired:" << p_str_w1.expired() << std::endl;
std::cout << "A use_count:" << p_str_w1.use_count() << std::endl;
p_str_a.reset();
p_str_a2.reset();
std::cout << "B expired:" << p_str_w1.expired() << std::endl;
std::cout << "B use_count:" << p_str_w1.use_count() << std::endl;
重复析构
初始指针只能赋值一次给shared_ptr,之后的shared_ptr的初始化只能由其它shared_ptr初始化,防止重复析构。
错误示例:
int *p_i = new int;
std::shared_ptr<int> sp1_i(p_i);
std::shared_ptr<int> sp2_i(p_i); // ERROR!!! 会产生两次析构
正确用法:
int *p_i = new int;
std::shared_ptr<int> sp1_i(p_i);
std::shared_ptr<int> sp2_i(sp1_i);
enable_shared_from_this
为了解决对象内this指针多次被shared_ptr类声明时需要使用
示例:
Class Data: std::enable_shared_from_this<Data> {
std::shared<Data> get_share_ptr() {
return std::shared_from_this();
}
}
类内使用 std::shared_from_this()函数即可获得this的shared_ptr。
强制转换为普通指针
std::shared_ptr<void> sp(new int);
std::static_pointer_cast<int *>(sp);
线程安全
// std::shared_ptr<int> g_int;
// {
// std::shared_ptr<int> local_int = std::make_shared<int>(10);
// std::atomic_store(&g_int, local_int);
// }
2、unique_ptr(独占式内存)
初始化
// 不允许复制语法赋初值
// std::unique_ptr<int> tmp_i = new int; // ERROR
std::unique_ptr<int> tmp_i(new int); // OK
重置赋值
std::unique_ptr<int> uptr;
uptr.reset(new int); // 重置赋值
释放使用权
uptr.release(); // 释放使用权 uptr.reset() 或 uptr = nullptr;
安全判断
//方法1:
if (uptr) {
std::cout << "uptr = " << *uptr << std::endl;
}
//方法2: if (uptr != nullptr)
//方法3: if (uptr.get() != nullptr)
拷贝(值传递)
std::unique_ptr<int> up1(new int);
// std::unique_ptr<int> up2(up1); // ERROR
std::unique_ptr<int> up2(std::move(up1));
unique_ptr作为函数参数:调用者必须手动调用std::move()
unique_ptr作为函数返回值:C++ 11编译器规定return语句不需要显式的调用std::move(),会自动调用std::move()
unique_ptr的偏特化:数组
数组初始化
std::unique_ptr<std::string[]> up_str(new std::string[10]);
定义deleter
// 错误
// std::unique_ptr<int> p_arr1(new int[10],
// [](int *arr) {
// std::cout << "delete array."<< std::endl;
// delete []arr;
// });
// 正确方法1
std::unique_ptr<int,void(*)(int*)> p_arr2(new int[10],
[](int *arr) {
std::cout << "delete array2."<< std::endl;
delete []arr;
});
// 正确方法2
std::unique_ptr<int,std::function<void(int*)>> p_arr3(new int[10],
[](int *arr) {
std::cout << "delete array2."<< std::endl;
delete []arr;
});
// 方法3
auto fun_del = [](int *arr) {
std::cout << "delete array2."<< std::endl;
delete []arr;
};
// 方法4 利用alias
using unique_ptr_int = std::unique_ptr<int, void(*)(int*)>;
unique_ptr_int up_aa(new int[10], [](int *arr) {
std::cout << "delete array2."<< std::endl;
delete []arr;
});
deleter深度挖掘
对于deleter,除了内存上的释放,还可以析构其它资源(如:文件句柄、socket句柄、共享内存等等)
示例如下:析构文件
std::unique_ptr<std::ofstream, void(*)(std::ofstream*)> p_ofs(new std::ofstream("text.txt"),
[](std::ofstream *ofs) {
std::cout << "delete ofstream" << std::endl;
ofs->close();
delete ofs;
});