十、 C++特性之智能指针

Smart Pointers 智能指针

已经有成千上万的文章讨论这个问题了,所以我只想说:现在能使用的,带引用计数,并且能自动释放内存的智能指针包括以下几种:

  • unique_ptr: 如果内存资源的所有权不需要共享,就应当使用这个(它没有拷贝构造函数),但是它可以转让给另一个unique_ptr(存在move构造函数)。
  • shared_ptr:  如果内存资源需要共享,那么使用这个(所以叫这个名字)。
  • weak_ptr: 持有被shared_ptr所管理对象的引用,但是不会改变引用计数值。它被用来打破依赖循环(想象在一个tree结构中,父节点通过一个共享所有权的引 用(chared_ptr)引用子节点,同时子节点又必须持有父节点的引用。如果这第二个引用也共享所有权,就会导致一个循环,最终两个节点内存都无法释 放)。

另一方面,auto_ptr已经被废弃,不会再使用了。

什么时候使用unique_ptr,什么时候使用shared_ptr取决于对所有权的需求,我建议阅读以下的讨 论:http://stackoverflow.com/questions/15648844/using-smart-pointers-for- class-members

以下第一个例子使用了unique_ptr。如果你想把对象所有权转移给另一个unique_ptr,需要使用std::move(我会在最后几段讨论这个函数)。在所有权转移后,交出所有权的智能指针将为空,get()函数将返回nullptr。

 1 void foo(int* p) 
 2 { 
 3 std::cout << *p << std::endl; 
 4 } 
 5 std::unique_ptr<int> p1(new int(42)); 
 6 std::unique_ptr<int> p2 = std::move(p1); // transfer ownership 
 7   
 8 if(p1) 
 9 foo(p1.get()); 
10   
11 (*p2)++; 
12   
13 if(p2) 
14 foo(p2.get()); 

第二个例子展示了shared_ptr。用法相似,但语义不同,此时所有权是共享的。

 1 void foo(int* p) 
 2 { 
 3 } 
 4 void bar(std::shared_ptr<int> p) 
 5 { 
 6 ++(*p); 
 7 } 
 8 std::shared_ptr<int> p1(new int(42)); 
 9 std::shared_ptr<int> p2 = p1; 
10   
11 bar(p1); 
12 foo(p2.get()); 

第一个声明和以下这行是等价的:

1 auto p3 = std::make_shared<int>(42); 

make_shared<T>是一个非成员函数,使用它的好处是可以一次性分配共享对象和智能指针自身的内存。而显示地使用 shared_ptr构造函数来构造则至少需要两次内存分配。除了会产生额外的开销,还可能会导致内存泄漏。在下面这个例子中,如果seed()抛出一个 错误就会产生内存泄漏。

1 void foo(std::shared_ptr<int> p, int init) 
2 { 
3 *p = init; 
4 } 
5 foo(std::shared_ptr<int>(new int(42)), seed()); 

如果使用make_shared就不会有这个问题了。第三个例子展示了weak_ptr。注意,你必须调用lock()来获得被引用对象的shared_ptr,通过它才能访问这个对象。

 1 auto p = std::make_shared<int>(42); 
 2 std::weak_ptr<int> wp = p; 
 3   
 4 { 
 5 auto sp = wp.lock(); 
 6 std::cout << *sp << std::endl; 
 7 } 
 8   
 9 p.reset(); 
10   
11 if(wp.expired()) 
12 std::cout << "expired" << std::endl; 

如果你试图锁定(lock)一个过期(指被弱引用对象已经被释放)的weak_ptr,那你将获得一个空的shared_ptr.

posted @ 2014-12-26 15:58  击进的Cocos  阅读(242)  评论(0编辑  收藏  举报