RAII的本质是用栈对象来管理资源,因为栈对象在离开作用域时,会自动调用析构函数
官方手册:https://en.cppreference.com/w/cpp/memory
unique_ptr
独享所有权,不能进行赋值或者赋值。不过定义了移动构造函数和移动赋值运算符函数
unique_ptr<std::string> uptr(new std::string("hello"));
std::vector<unique_ptr<std::string>> vecInt;
vecInt.push_back(std::move(uptr)) // uptr是左值,放入到容器中会调用unique_ptr的复制构造函数,因此需要用std::move将其转换为右值放入,注意uptr被放入容器后,uptr托管的对象就转移到容器之中了,不能再使用
uptr.reset(new std::string("world")); // reset重新托管一个新对象
shared_ptr
// shared_ptr是共享所有权的智能指针,在复制和赋值的时候,引用计数加1
std::shared_ptr<std::string> sptr(new std::string("hello"));
std::shared_ptr<std::string> sptr2(sptr); // 复制
std::cout << sptr.use_count() << std::endl; // use_count 返回引用计数
weak_ptr
shared_ptr循环引用会导致内存泄露,因此引入了weak_ptr
// shared_ptr循环引用
class Child;
class Parent
{
public:
Parent() { cout << "Parent()" << endl; }
~Parent() { cout << "~Parent()" << endl; }
shared_ptr<Child> _childPtr; // 将Parent或Child中的一个改为weak_ptr即可解决循环依赖的问题
};
class Child
{
public:
Child() { cout << "Child()" << endl; }
~Child(){ cout << "~Child()" << endl; }
shared_ptr<Parent> _parentPtr;
};
int main(void)
{
// 执行结果可以看到Parent和Child的析构函数没有得到执行,shared_ptr托管的堆内存没有释放
// shared_ptr的循环引用会导致内存泄漏
shared_ptr<Parent> pParent(new Parent());
shared_ptr<Child> pChild(new Child());
cout << "pParent'use_count = " << pParent.use_count() << endl;
cout << "pChild'use_count = " << pChild.use_count() << endl;
pParent->_childPtr = pChild;
pChild->_parentPtr = pParent;
cout << "pParent'use_count = " << pParent.use_count() << endl;
cout << "pChild'use_count = " << pChild.use_count() << endl;
return 0;
}
weak_ptr是弱引用智能指针,shard_ptr是强引用智能指针
weak_ptr不能直接托管对象,只能通过如下方式构造
weak_ptr可以通过lock()方法提升为一个shared_ptr
注意事项
例1:
不要将一个原生裸指针交给两个不同的智能指针去托管
class Point{
public:
Point(int x, int y) : _ix(x), _iy(y) { std::cout << "Point::Point()" << std::endl;}
~Point() { std::cout << "Point::~Point()" << std::endl;}
// 在
shared_ptr<Point> addPoint(Point* pt)
{
_ix += pt->_ix;
_iy += pt->_iy;
}
private:
int _ix;
int _iy;
};
/* 执行结果为
Point::Point()
Point::~Point()
Point::~Point()
可以看到将同一个原生裸指针交给两个不同的智能指针去托管的时候发生了double free
*/
int main()
{
Point pt = new Point(1,2);
shared_ptr<Point> sptr(pt);
shared_ptr<Point> sptr2(pt);
}
例2:
在类内部获取本对象的智能指针借助std::enable_shared_from_this
class Point
: public std::enable_shared_from_this<Point>
{
public:
Point(int x, int y) : _ix(x), _iy(y) {}
// 在
shared_ptr<Point> addPoint(Point* pt)
{
_ix += pt->_ix;
_iy += pt->_iy;
return shared_from_this();
// return shared_ptr<Point>(this); 这种写法不对,这会造成这里的shared_ptr和sptr托管了同一个对象,导致double free
}
private:
int _ix;
int _iy;
};
int main()
{
shared_ptr<Point> sptr(new Point(1,2));
shared_ptr<Point> sptr2(new Point(3, 4));
shared_ptr<Point> sptr3(sptr->addPoint(sptr2.get()));
}
例3:
如果托管的对象不是指针,类似FILE类型,指定删除器回收资源
struct FilePointerCloser
{
void operator()(FILE * fp){
if(fp)
{
fclose(fp);
cout << "> fclose(fp)" << endl;
}
}
};
int main()
{
std::shared_ptr<FILE> sp(fopen("test.txt", "w+"), FilePointerCloser());
std::string msg("hello,world\n");
fwrite(msg.c_str(), msg.size(), 1, sp.get());
}