C++智能指针

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());
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值