目录
简单点,不要用指针,用类的实例解决问题
如果要用指针,不要用裸指针,优先考虑unique_ptr,其次是shared_ptr
unique_ptr
基本用法
#include <iostream>
#include <memory>
using std::cout;
using std::endl;
// 不能拷贝unique_ptr的规则有一个例外:我们可以拷贝或赋值一个将要被销毁的unique_ptr,将亡值
std::unique_ptr<int> func1(int a)
{
return std::unique_ptr<int> (new int(a));
}
std::unique_ptr<int> func2(int a)
{
std::unique_ptr<int> localVar{new int(a)};
return localVar;
}
// 传unique_ptr参数可以使用引用避免所有权的转移,或者暂时的移交所有权
void func3(std::unique_ptr<int> &up)
{
cout << "in func3, *up: " << *up << endl;
}
std::unique_ptr<int> func4(std::unique_ptr<int> up)
{
// up相当于局部变量
cout << "in func4, *up: " << *up << endl;
return up;
}
void func()
{
int *x {new int(100)};
std::unique_ptr<int> up1, up2;
// 不要与裸指针混用
// 会使up1 up2指向同一个内存
up1.reset(x);
up2.reset(x);
}
int main()
{
std::unique_ptr<int> up1{new int(100)};
//std::unique_ptr<int> up1; // *up1 出错,空智能指针也不能解引用
cout << "*up1 : " << *up1 << endl;
// 构造函数是explicit,不支持隐式转换,int * 不能给std::unique_ptr
//std::unique_ptr<int> up2 = new int(10);
// 不允许拷贝
// std::unique_ptr<int> up3(up1);
// unique_ptr拥有它所指向的对象,在某一时刻,只能有一个unique_ptr指向特定的对象
// 当unique_ptr被销毁时,它所指向的对象也会被销毁
// up1 = nullptr; // 释放up1指向的对象,并将up1置为空
std::unique_ptr<int> up2 {new int(10)};
// 参数可以为 空、内置指针,先将up所指对象释放,然后重置up的值
// up1.reset(up2); // 不允许
up1.reset(new int(20));
cout << "after reset : *up1 " << *up1 << endl;
// up放弃对它所指对象的控制权,并返回保存的指针,将up置为空
// 但不会释放内存,所以要手动delete
auto p_int = up1.release();
delete p_int;
// 传递unique_ptr
up1 = func1(200);
cout << "return unique_ptr : " << *up1 << endl;
up1 = nullptr;
up1 = func2(300);
cout << "return unique_ptr : " << *up1 << endl;
func3(up1); // 传递引用,不拷贝,不涉及所有权转移
// 暂时转移所有权,函数结束时返回拷贝,重新收回所有权
up1 = func4(std::unique_ptr<int>(up1.release()));
// 陷阱
func();
return 0;
}
#include <vector>
#include <typeinfo>
#include<memory>
#include <iostream>
class Person
{
public:
~Person()
{
std::cout << "delete" << std::endl;
}
};
void func(std::unique_ptr<Person> uqi)
{
std::cout << "in func" << std::endl;
}
int main(void)
{
std::unique_ptr<Person> uqi {new Person};
func(std::unique_ptr<Person>(uqi.release()));
std::cout << "ok" << std::endl;
return 0;
}
/*
in func
delete
ok
*/
std::move
#include <iostream>
#include <memory>
using std::cout;
using std::endl;
int main(int argc, char * argv[])
{
// 智能指针独占指向的对象
std::unique_ptr<double> pdata(new double{ 99.9 });
*pdata = 100.0;
cout << *pdata << endl;
std::unique_ptr<double> pdata1;
pdata1 = std::move(pdata); // 不能直接赋值给其他智能指针,必须用move
cout << *pdata1 << endl;
cout << pdata << endl;
return 0;
}
*unique_ptr
#include <iostream>
#include <memory>
using std::cout;
using std::endl;
int main()
{
std::unique_ptr<int> up1{new int(100)};
cout << "*up1 : " << *up1 << endl;
std::unique_ptr<int> up2{new int(200)};
cout << "*up2 : " << *up2 << endl;
cout << "up1 ptr: " << up1.get() << endl;
cout << "up2 ptr: " << up2.get() << endl;
*up1 = *up2; // up1指向空间的值更改为200
cout << "*up1: " << *up1 << endl;
cout << "up1 ptr: " << up1.get() << endl;
cout << "up2 ptr: " << up2.get() << endl;
return 0;
}
get方法
cppplusplus.com例子
// unique_ptr::get vs unique_ptr::release
#include <iostream>
#include <memory>
int main () {
// foo bar p
// --- --- ---
std::unique_ptr<int> foo; // null
std::unique_ptr<int> bar; // null null
int* p = nullptr; // null null null
foo = std::unique_ptr<int>(new int(10)); // (10) null null
bar = std::move(foo); // null (10) null
p = bar.get(); // null (10) (10)
*p = 20; // null (20) (20)
p = nullptr; // null (20) null
foo = std::unique_ptr<int>(new int(30)); // (30) (20) null
p = foo.release(); // null (20) (30)
*p = 40; // null (20) (40)
std::cout << "foo: ";
if (foo) std::cout << *foo << '\n'; else std::cout << "(null)\n";
std::cout << "bar: ";
if (bar) std::cout << *bar << '\n'; else std::cout << "(null)\n";
std::cout << "p: ";
if (p) std::cout << *p << '\n'; else std::cout << "(null)\n";
std::cout << '\n';
delete p; // the program is now responsible of deleting the object pointed to by p
// bar deletes its managed object automatically
return 0;
}
shared_ptr
基本用法
#include <iostream>
#include <memory>
using std::cout;
using std::endl;
// 不要用p.get()的返回值为shared_ptr赋值
void func()
{
std::shared_ptr<int> sp1(new int(10));
// sp2保存了sp1的指针
// 想法是 sp1和sp2的use_count都是2
// 但是sp1和sp2的use_count都是1
// sp1释放后,指向的空间被释放
// 但是呢,sp2还没有被释放,可以指向的空间已经被释放了
// std::shared_ptr<int> sp2(sp1);
std::shared_ptr<int> sp2(sp1.get());
cout << "sp1 use_count: " << sp1.use_count() << endl; // 1
cout << "sp2 use_count: " << sp2.use_count() << endl;
}
void func1()
{
int *x(new int(10));
std::shared_ptr<int> sp1(x);
std::shared_ptr<int> sp2(x);
// sp1、sp2都指向x所指的内存,但它们是独立的
// 那么这就很危险了,失去了共享指针的意义
cout << "sp1 ptr: " << sp1.get() << endl;
cout << "sp2 ptr: " << sp2.get() << endl;
cout << "sp1 use_count: " << sp1.use_count() << endl; // 1
cout << "sp2 use_count: " << sp2.use_count() << endl;
}
int main()
{
// 尽量用make_shared
std::shared_ptr<int> sp(new int);
cout << sp.use_count() << endl; // 1
sp = std::make_shared<int>(100);
cout << sp.use_count() << endl; // 1
// explicit
// error,不能进行隐式转换
// std::shared_ptr<int> sp1 = new int(100);
std::shared_ptr<int> sp1(new int(200));
cout << "sp use_count: " << sp.use_count() << endl; // 1
cout << "sp1 use_count: " << sp1.use_count() << endl;
sp = sp1;
cout << "sp use_count: " << sp.use_count() << endl; // 2
cout << "sp1 use_count: " << sp1.use_count() << endl;
// func();
func1();
return 0;
}
自定义删除器
基础
"shared_ptr"的传递删除器(deleter)方式比较简单, 只需要在参数中添加具体的删除器函数名, 即可; 注意是单参数函数;
#include <iostream>
#include <typeinfo>
#include <vector>
using std::cout;
using std::endl;
void deleter(int *ptr)
{
delete ptr;
ptr = nullptr;
cout << "smart ptr delete the pointer" << endl;
}
int main(void)
{
std::shared_ptr<int> sp1(new int(10), deleter);
std::shared_ptr<int> sp2(new int, deleter);
cout << typeid(sp2).name() << endl;
// sp2用定义的deleter释放原来的内存
// 改成了 make_shared<int>的智能指针,但是这个智能指针用的是默认删除器
sp2 = std::make_shared<int>(15);
// make_shared<int>返回的指针是默认删除器,而sp2定义的时候是自定义的删除器
// 但是呢 两者可以赋值,说明两者是同一类型,这一点和unique_ptr不一样
cout << typeid(sp2).name() << endl;
cout << "*sp1 = " << *sp1 << endl;
cout << "*sp2 = " << *sp2 << endl;
return 0;
}
/*
class std::shared_ptr<int>
smart ptr delete the pointer // 释放原来的空间
class std::shared_ptr<int>
*sp1 = 10
*sp2 = 15
smart ptr delete the pointer
*/
"unique_ptr"的删除器是函数模板(function template), 所以需要在模板类型传递删除器的类型(即函数指针(function pointer)), 再在参数中添加具体删除器;定义函数指针的类型, 包含三种方法(typedef, typedef decltype, using), 也可以直接传递decltype;
#include <iostream>
#include <typeinfo>
#include <vector>
using std::cout;
using std::endl;
void deleter(int *ptr)
{
delete ptr;
ptr = nullptr;
cout << "smart ptr delete the pointer" << endl;
}
int main(void)
{
// 函数指针的几种定义方法
typedef void (*tp)(int *);
typedef decltype(deleter)* dp;
using up = void (*)(int*);
// decltype(deleter) 是函数类型
// 传递函数指针,decltype(deteter) * 才是函数类型的指针
std::unique_ptr<int, decltype(deleter)*> upi(new int(20), deleter);
std::unique_ptr<int, tp> upi1(new int(30), deleter);
std::unique_ptr<int, dp> upi2(new int(35), deleter);
std::unique_ptr<int, up> upi3(new int(40), deleter);
std::unique_ptr<int> upi4(new int(0)); // 默认删除器
cout << "upi typeid: " << typeid(upi).name() << endl;
cout << "upi1 typeid: " << typeid(upi1).name() << endl;
cout << "upi2 typeid: " << typeid(upi2).name() << endl;
cout << "upi3 typeid: " << typeid(upi3).name() << endl;
cout << "upi4 typeid: " << typeid(upi4).name() << endl; // 不同的删除器的unique_ptr,类型不相同
return 0;
}
/*
upi typeid: class std::unique_ptr<int,void (__cdecl*)(int * __ptr64)>
upi1 typeid: class std::unique_ptr<int,void (__cdecl*)(int * __ptr64)>
upi2 typeid: class std::unique_ptr<int,void (__cdecl*)(int * __ptr64)>
upi3 typeid: class std::unique_ptr<int,void (__cdecl*)(int * __ptr64)>
upi4 typeid: class std::unique_ptr<int,struct std::default_delete<int> >
smart ptr delete the pointer
smart ptr delete the pointer
smart ptr delete the pointer
smart ptr delete the pointer
*/
删除数组指针
如果定义了一个数组的智能指针,按道理需要用delete [] raw pointer,那么就必须指定删除器了
#include <iostream>
#include <typeinfo>
#include <vector>
using std::cout;
using std::endl;
void deleter(int *ptr)
{
delete[] ptr;
ptr = nullptr;
cout << "smart ptr delete the pointer" << endl;
}
int main(void)
{
// 自定义删除器
// c++17也有数组写法了
std::shared_ptr<int> spi(new int[10], deleter);
// unique_ptr有这样的数组写法
std::unique_ptr<int []> upi(new int[10]);
return 0;
}