auto_ptr

  • 解决什么问题

  • 有什么问题

shared_ptr

  • 解决问题

原来 c 里的思路,一个全局共享的对象,n 多地方可以用指针指向,并使用它,但谁来释放,何时释放?

如果用 shared_ptr,不用关心谁释放,最后 1 个 shared_ptr 失效,则该对象被释放。

shared_ptr采用引用计数的方式管理所指向的对象。引用值代表当前有多少个 shared_ptr 引用了该对象。当引用值为 0 时,shared_ptr 将自动析构所引用的对象。

shared_ptr<Obj> ptr1(new Obj(1) );  // ref =1
shared_ptr<Obj> ptr2(new Obj(2) );  // ref =1

ptr1 = ptr2 ;

ptr2,ptr1 的引用对象均为 Obj(2)。新的引用导致 ptr1 的新对象 ref+1,旧的引用对象 ref-1,为 0,则调用 Obj()的析构;

可以尽情的用 share_ptr 代替 c 的裸指针,再也不用担心资源释放的问题,RAII 神器。

  • make_shared

auto + make_shared 可以轻松创建 shared_ptr; auto p = make_shared<T>(args) ;

unique_ptr

unique_ptr对于所指向的对象,正如其名字所示,是 独占 的。所以,不可以对 unique_ptr 进行拷贝、赋值等操作,但是可以通过 release 函数在 unique_ptr 之间转移控制权。

release是 unique 独有的,仅仅是剥离出原对象,即智能指针不再包裹原对象。而不析构对象。

但有 2 个特殊情况,即 unique_ptr 可以作为函数的返回值和参数使用,这时虽然也有隐含的拷贝存在,但是并非不可行的。

unique_ptr<Obj> ptr1(new Obj(1) );  // ref =1
unique_ptr<Obj> ptr2(new Obj(2) );  // ref =1

unique_ptr<Obj> ptr3 = unique_ptr<Obj>(ptr1);  // not allowed

ptr1 = ptr2 // not allowed

//交换两个unique_ptr的控制权
auto tmp = ptr1.release();
ptr1.reset(ptr2.release());
ptr2.reset(tmp);

unique_ptr<string> func(unique_ptr<string> ptr) {...}

auto ptr3 = func(ptr1); //ok

weak_ptr

weak_ptr一般和 shared_ptr 配合使用。它可以指向 shared_ptr 所指向的对象,但是却不增加对象的引用计数。这样就有可能出现 weak_ptr 所指向的对象实际上已经被释放了的情况。因此,weak_ptr 有一个 lock 函数,尝试取回一个指向对象的 shared_ptr。

weak_ptr<Demo>  weak_ptr_test()
{
	auto shared =  make_shared<Demo>("sunny");
	auto weaked = weak_ptr<Demo>(shared);

	cout << "shared show";
	shared->show();


	cout << "weak show";
	auto result =  weaked.lock();
	if(result != NULL)
		result->show();

	shared.reset();

	cout << "weak expired val after reset " << weaked.expired() << endl;

	shared = make_shared<Demo>("rainy");

	cout << "weak expired val after = " << weaked.expired() << endl;

	return weaked;
}

	auto weaked = weak_ptr_test();
	cout << "weak expired val after returned " << weaked.expired() << endl;

执行结果为

Demo sunny created
shared showDemo sunny lived
weak showDemo sunny lived
weak expired val after reset 0
Demo rainy created
weak expired val after = 0
Demo sunny destroyed
Demo rainy destroyed
weak expired val after returned 1

共享指针里的 get,reset

get表示拿到原始指针,此时原始对象还是包裹在智能指针里的,但不推荐用 get 的方式去访问原对象。

reset表示释放原引用对象,并 reset 为新的对象。

auto ptr = make_shared<string>("love");
string* orig = ptr.get(); //即orig 指向"love"

ptr.reset(new string("peace")); //释放原来的love,装载新的peace。