[c++11]智能指针部分学习

shared_ptr

动态的应用场景

  1. 程序不知道自己需要使用多少对象
  2. 程序不知道对象的准确类型
  3. 程序需要在多个对象间共享数据

不推荐使用new,delete直接管理内存

  1. 忘记释放内存
  2. 使用已经释放掉的内存
  3. 同一块内存释放两次

ps:想象一下,如果new 出对象在delete前的操作中,程序崩溃,该段内存必然会泄漏….

初始化一个智能指针

///使用new初始化(直接初始化)
shared_ptr<int> p1 (new int(1024));
///工厂函数使用
shared_ptr<int> clone (int p){
    return shared_ptr<int> p2 (new int(p));
}

简单用法

shared_ptr<int> p1 (new int(1024));
///当前引用计数
p1.use_count();
///判断p1是否是独占状态即(引用数为1)(函数已经弃用?)
p1.unique();
///q是重新绑定的指针,d是传递的删除器,将调用d来删除,若无该两个参数,且p1独占指向的对象,则释放内存。
p1.reset(q,d);
///交换指针 p1 和 q 交换指针
p1.swap(q);
///定义的时候就自带删除器
shared_ptr<T> p2 (new int(*p1),d);
///转换成智能指针
auto p2 = make_shared<int>(42);

不要使用get()对另一个智能指针赋值,或初始化。

get得到的指针单独计数,当和它指向同一块内存区的智能指针销毁后,它将变得无效。

reset用于更新引用计数(动态绑定),需要时释放p指向的对象

实例

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

int main() {
  //shared_ptr<int> p1 (new int(1024));
  shared_ptr<string> p(new string("helloworld"));
  string *q = p.get();
  cout<<"引用次数"<<p.use_count()<<endl;
  shared_ptr<string> p1 = p;
  cout<<"引用次数"<<p.use_count()<<endl;

  [&p]{
    if(!p.unique()){
      p.reset(new string(*p));
      cout<<"引用次数"<<p.use_count()<<endl;
      cout<<"reset"<<endl;
    }
    *p += "111";
  }();

  cout<<"引用次数"<<p1.use_count()<<endl;
  cout<<*q<<endl;
  std::cout << *p<<endl;
  std::cout<< *p1;
}

运行结果

引用次数1
引用次数2
引用次数1
reset
引用次数1
helloworld
helloworld111
helloworld   

说明 从结果可知,在lambda函数前p的引用达到2次,
但reset后变为1次,原因是p在reset时动态绑定,指向了新的对象,只剩p1指向原对象,而现在的p和p1,q都指向不同的内存因而,计数都为1.

注意 get()得到的q指针是一个独立计数的指针,虽然也和p1一样指向原先q所占用的那块内存。

智能指针陷阱

  1. 不使用相同的内置指针初始化(或reset)多个智能指针。
  2. 不delete get()返回的指针。
  3. 不使用get()初始化或reset另一智能指针
  4. get得到的指针单独计数,当和它指向同一块内存区的智能指针销毁后,它将变得无效。
  5. 如果你使用智能指针管理的资源不是new分配的内存,记得传递给他一个删除器(示例如下)

网络编程中的断开连接实例

void process(destination &d ){
    ///创建一个连接对象
    connection c = connect(&d);
    ///为保证连接在f退出或异常退出时正常关闭connection (传递了一个删除器end_connection)
    shared_ptr<connection> p_connection(&c , end_connection);
}
///退出函数在p销毁时调用end_connection()
void end_connection( connection *p){
    p->disconnect(*p);
}

unique_ptr ( auto_ptr的完善版 )

简单用法

///提供了删除器但声明时的形式不同
unique_ptr<T,D> u1;
unique_ptr<T,D> u2(d);
///将u1置空,返回指针控制权
u1.release();
///注意,unique_ptr不能被拷贝或赋值!!只能接收控制权。

实例

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

int main() {

  ///通过传递指针控制权,我们可以初始化其他的智能指针
  unique_ptr<string> p1(new string("hello"));
  string strx = "world";
  ///p1放弃对指针的控制权,转给p2
  unique_ptr<string> p2(p1.release());
  cout << "p2: " << *p2 << endl;
  unique_ptr<string> p3(new string("goodbye"));
  cout << "p3: " << *p3 << endl;
  ///p3放弃对指针的控制权,转给p2,通过动态绑定。
  p2.reset(p3.release());
  cout << "p2: " << *p2 << endl;

  ///需要负责扫尾工作(向unique_str传递删除器,如果不传递会调用default_delete来删除)
  unique_ptr<string,default_delete<string>> p_end(p2.release(),default_delete<string>());

}

weak_ptr

简单用法

///和shared_ptr sp指向同一对象,但他只是弱共享。不会影响sp的引用计数
weak_ptr<T> w(sp);
w = sp;
///expired如果use_count()等于0,返回true,否则false,用于检测共享对象是否存在。
w.expired();
///若共享对象还存在,则返回一个可使用的shared_ptr,增加引用计数。
w.lock();

weak_ptr像是为了修补无法预计的get准备的。

实例

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

int main() {
  ///为sp1创建一个弱共享wp
  shared_ptr<string> sp1(new string("hello"));
  weak_ptr<string> wp(sp1);
  ///释放sp1的内存
  sp1.reset();
  ///若lock成功则可以使用temp1,失败则temp1为空,无法使用
  if(shared_ptr<string> temp1 = wp.lock())
    cout<<*temp1<<endl;

}

参考

猜你喜欢

转载自blog.csdn.net/llwodao/article/details/79989290