C++11:智能指针

   在 C++ 98 中,智能指针通过一个模板类型 auto_ptr 来实现。auto_ptr 以对象的方式管理堆分配的内存,并且在适当的时间(比如析构),释放获得的堆上的内存。这种堆内存管理的方式只需要程序员将 new 运算符操作返回的指针作为 auto_ptr 的初始值计科,不去要在显示的调用 delete 释放。

  这在一定程度上避免了忘记释放堆内存造成的一系列问题。但是 auto_ptr 有一些缺点例如:
拷贝时返回一个左值、不能调用 delete[]。C++ 11 中弃用了 auto_ptr,改用 unique_ptrshared_ptrweak_ptr等智能指针来自动回收堆上分配的内存。

unique_ptr

  unique_ptr 持有对对象的独有权,同一时刻只能有一个 unique_ptr 指向给定对象(通过禁止拷贝语义、只有移动语义来实现)。

   unique_ptr 指针本身的生命周期:从 unique_ptr 指针创建时开始,直到离开作用域。

  离开作用域时,若其指向对象,则将其所指对象销毁(默认使用 delete 操作符,用户可指定其他操作)。

void test1() {
	unique_ptr<int> up1(new int(11)); // 无法复制的unique_ptr
	//unique_ptr<int> up2 = up1;        // err, 不能通过编译
	cout << *up1 << endl;  //11

	unique_ptr<int> up3 = move(up1); // 现在p3是数据的唯一的unique_ptr
	cout << *up3 << endl;   // 11
	//cout << *up1 << endl;   // err, 运行时错误
	up3.reset();// 显式释放内存
	up1.reset();            // 不会导致运行时错误
	//cout << *up3 << endl;   // err, 运行时错误

	unique_ptr<int> up4(new int(22));// 无法复制的unique_ptr
	up4.reset(new int(44));//"绑定"动态对象
	cout << *up4 << endl;

	up4 = nullptr;//显式销毁所指对象,同时智能指针变为空指针。与up4.reset()等价
	unique_ptr<int> up5(new int(55));
	int* p = up5.release(); //只是释放控制权,不会释放内存
	cout << *p << endl;
	//cout << *up5 << endl; // err, 运行时错误
	delete p; //释放堆区资源
}

shared_ptr

  shared_ptr 允许多个该智能指针共享第“拥有”同一堆分配对象的内存,这通过引用计数(reference counting)实现,会记录有多少个 shared_ptr 共同指向一个对象,一旦最后一个这样的指针被销毁,也就是一旦某个对象的引用计数变为 0,这个对象会被自动删除。

void test2() {
	shared_ptr<int> sp1(new int(22));
	shared_ptr<int> sp2 = sp1;
	cout << "count: " << sp2.use_count() << endl; //打印引用计数

	cout << *sp1 << endl;   // 22
	cout << *sp2 << endl;   // 22

	sp1.reset();    //显式让引用计数减1
	cout << "count: " << sp2.use_count() << endl; //打印引用计数

	cout << *sp2 << endl;   // 22
}

weak_ptr

  weak_ptr 是为配合 shared_ptr 而引入的一种智能指针来协助 shared_ptr 工作,它可以从一个 shared_ptr 或另一个 weak_ptr 对象构造,它的构造和析构不会引起引用计数的增加或减少。没有重载 *-> 但可以使用 lock 获得一个可用的 shared_ptr 对象。

  weak_ptr 的使用更为复杂一点,它可以指向 shared_ptr 指针指向的对象内存,却并不拥有该内存,而使用 weak_ptr 成员 lock,则可返回其指向内存的一个 share_ptr 对象,且在所指对象内存已经无效时,返回指针空值 nullptr。这在验证 share_ptr 智能指针的有效性上会很有作用。

#include <iostream>
#include <memory>
#include <string>
using namespace std;

void test1() {
	unique_ptr<int> up1(new int(11)); // 无法复制的unique_ptr
	//unique_ptr<int> up2 = up1;        // err, 不能通过编译
	cout << *up1 << endl;  //11

	unique_ptr<int> up3 = move(up1); // 现在p3是数据的唯一的unique_ptr
	cout << *up3 << endl;   // 11
	//cout << *up1 << endl;   // err, 运行时错误
	up3.reset();// 显式释放内存
	up1.reset();            // 不会导致运行时错误
	//cout << *up3 << endl;   // err, 运行时错误

	unique_ptr<int> up4(new int(22));// 无法复制的unique_ptr
	up4.reset(new int(44));//"绑定"动态对象
	cout << *up4 << endl;

	up4 = nullptr;//显式销毁所指对象,同时智能指针变为空指针。与up4.reset()等价
	unique_ptr<int> up5(new int(55));
	int* p = up5.release(); //只是释放控制权,不会释放内存
	cout << *p << endl;
	//cout << *up5 << endl; // err, 运行时错误
	delete p; //释放堆区资源
}

void test2() {
	shared_ptr<int> sp1(new int(22));
	shared_ptr<int> sp2 = sp1;
	cout << "count: " << sp2.use_count() << endl; //打印引用计数

	cout << *sp1 << endl;   // 22
	cout << *sp2 << endl;   // 22

	sp1.reset();    //显式让引用计数减1
	cout << "count: " << sp2.use_count() << endl; //打印引用计数

	cout << *sp2 << endl;   // 22
}

template<class T>
void Check(weak_ptr<T>& wp) {
	shared_ptr<T> sp = wp.lock();
	if(sp == nullptr)
		cout << "pointer is invalid" << endl;
	else
		cout << "still " << *sp << endl;
}

void test3() {
	shared_ptr<int> sp1(new int(22));
	shared_ptr<int> sp2 = sp1;
	weak_ptr<int> wp = sp1; // 指向shared_ptr<int>所指对象

	cout << "count: " << wp.use_count() << endl; //打印计数器
	cout << *sp1 << endl;   // 22
	cout << *sp2 << endl;   // 22
	Check(wp);
	cout << "-----------" << endl;

	sp1.reset();
	cout << "count: " << wp.use_count() << endl;
	cout << *sp2 << endl;   // 22
	Check(wp);              // still 22
	cout << "-----------" << endl;

	sp2.reset();
	cout << "count: " << wp.use_count() << endl;
	Check(wp);              // pointer is invalid
}

int main() {
	//test1();
	//test2();
	test3();
	return 0;
}