• c++ 资源回收学习


    c++ 资源回收学习

    • c++ 语言的资源回收

    使用 delete

    • 例子
      #include 
      
      int main()
      {
          int* tmpi = new int;
      
          *tmpi = 1;
          std::cout << *tmpi << "\n";
          delete tmpi;
      
          std::cout << *tmpi << "\n"; // 引发了异常: 读取访问权限冲突
      }
      

    这样的 delete基本回收资源操作,容易遗忘,或者是在函数中由于其他原因在中途出现异常或者被其他人 return返回操作,如下

    ```
    
    #include 
    
    void demo1(int a1) 
    {
        int* tmpi = new int;
    
        *tmpi = a1;
    
        if (*tmpi == 1)
        {
            return;
        }
    
        std::cout << *tmpi << "\n";
    
    
        delete tmpi;
    }
    
    int main()
    {
        demo1(0); // 正常释放
        demo1(1); // 没有释放
    }
    
    ```
    

    怎么防止这种没有正常释放资源操作

    1. 使用 class封装,c++ 的析构函数,在对象消亡时即自动被调用。

      #include 
      
      using namespace std;
      
      class Test {
      public:
          Test() {
              tmpi = new int;
          };
          ~Test() {
              if (tmpi)
              {
                  std::cout << "delete tmpi;" << "\n";
                  delete tmpi;
              }
          };
          void demo1(int a1) {
              *tmpi = a1;
      
              if (*tmpi == 1)
              {
                  return;
              }
      
              std::cout << *tmpi << "\n";
          };
      private:
          int* tmpi = nullptr;
      };
      
      int main()
      {
          Test t1;
          t1.demo1(0);
          t1.demo1(1);
      }
      
      
      • 程序运行输出
      0
      delete tmpi;
      
    2. 使用 智能指针

      #include 
      #include 
      
      using namespace std;
      
      int main()
      {
          // shared_ptr tmpi_1(new int);
          // shared_ptr tmpi_1 = make_shared(new int);
          int* check_tmpi_2 = nullptr;
      
          {
              shared_ptr tmpi_2(new int);
              *tmpi_2 = 2;
      
              // 获取 shared_ptr 托管的资源
              check_tmpi_2 = tmpi_2.get();
      
              std::cout << "tmpi_2:" << *tmpi_2 << "\n";
              std::cout << "check_tmpi_2:" << *check_tmpi_2 << "\n";
      
              // 出了作用域 释放掉托管的 tmpi_2
          }
      
          std::cout << "释放 check_tmpi_2:" << *check_tmpi_2 << "\n";
      
          int* tmpi_1 = new int; 
          *tmpi_1 = 1;
      
          {
              shared_ptr tmpi_ptr(tmpi_1);
      
              // 出了作用域 释放掉托管的 tmpi_1
          }
          
          std::cout << "释放 tmpi_1:" << *tmpi_1 << "\n"; // 输出 乱码,已经释放掉
      
      
      }
      
      
      
    3. 使用 lambda, 委托其他类回收, 这种方式更过适用于 closefandle(client);来回收资源的方式,[参考](http://mindhacks.cn/2012/08/27/modern-cpp-practices/)

      #include 
      #include 
      
      using namespace std;
      
      
      // --beg ScopeGuard
      #include 
      
      class ScopeGuard
      {
      public:
          explicit ScopeGuard(std::function onExitScope)
              : onExitScope_(onExitScope), dismissed_(false)
          { }
      
          ~ScopeGuard()
          {
              if (!dismissed_)
              {
                  onExitScope_();
              }
          }
      
          void Dismiss()
          {
              dismissed_ = true;
          }
      
      private:
          std::function onExitScope_;
          bool dismissed_;
      
      private: // noncopyable
          ScopeGuard(ScopeGuard const&);
          ScopeGuard& operator=(ScopeGuard const&);
      };
      
      #define SCOPEGUARD_LINENAME_CAT(name, line) name##line
      #define SCOPEGUARD_LINENAME(name, line) SCOPEGUARD_LINENAME_CAT(name, line)
      
      #define ON_SCOPE_EXIT(callback) ScopeGuard SCOPEGUARD_LINENAME(EXIT, __LINE__)(callback)
      // -- end ScopeGuard
      
      
      int main()
      {
          int *tmp = new int;
          ScopeGuard exitG([&] {
              if (tmp)
              {
                  std::cout << "delete tmp" << endl;
                  delete tmp;
              }
              });
      
          *tmp = 2;
          std::cout << "*tmp =" << *tmp << endl;
      }
      
      
      • 输出结果
        *tmp = 2
        delete tmp
        
    • windows 使用 socket 例子

      #include 
      #include 
      
          // --beg ScopeGuard
          #include 
      
          class ScopeGuard
          {
          public:
              explicit ScopeGuard(std::function onExitScope)
                  : onExitScope_(onExitScope), dismissed_(false)
              { }
      
              ~ScopeGuard()
              {
                  if (!dismissed_)
                  {
                      onExitScope_();
                  }
              }
      
              void Dismiss()
              {
                  dismissed_ = true;
              }
      
          private:
              std::function onExitScope_;
              bool dismissed_;
      
          private: // noncopyable
              ScopeGuard(ScopeGuard const&);
              ScopeGuard& operator=(ScopeGuard const&);
          };
      
          #define SCOPEGUARD_LINENAME_CAT(name, line) name##line
          #define SCOPEGUARD_LINENAME(name, line) SCOPEGUARD_LINENAME_CAT(name, line)
      
          #define ON_SCOPE_EXIT(callback) ScopeGuard SCOPEGUARD_LINENAME(EXIT, __LINE__)(callback)
          // -- end ScopeGuard
      
      
          #include   
          #pragma comment(lib,"ws2_32.lib")  
      
          int main()
          {
              WORD sockVersion = MAKEWORD(2, 2);
              WSADATA wsaData;
              if (WSAStartup(sockVersion, &wsaData) != 0)
              {
                  return 0;
              }
      
              //创建套接字  
              SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
              if (slisten == INVALID_SOCKET)
              {
                  printf("socket error !");
                  return 0;
              }
      
              // ON_SCOPE_EXIT 释放资源
              ScopeGuard exitG([&] {
                  printf("\n ON_SCOPE_EXIT 释放资源 ! \n");
                  closesocket(slisten);
                  WSACleanup();
                  });
      
              // 或者 ON_SCOPE_EXIT
              // ON_SCOPE_EXIT([&] {
              //    printf("\n ON_SCOPE_EXIT 释放资源 ! \n");
              //    //std::cout << "ON_SCOPE_EXIT" << "\n";
              //    closesocket(slisten);
              //    WSACleanup();
              //    });
      
      
              //绑定IP和端口  
              sockaddr_in sin;
              sin.sin_family = AF_INET;
              sin.sin_port = htons(10010);
              sin.sin_addr.S_un.S_addr = INADDR_ANY;
              if (bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)
              {
                  printf("bind error !");
              }
      
              //开始监听  
              if (listen(slisten, 5) == SOCKET_ERROR)
              {
                  printf("listen error !");
                  return 0;
              }
      
              SOCKET sClient;
              sockaddr_in remoteAddr;
              int nAddrlen = sizeof(remoteAddr);
              char revData[255];
              while (true)
              {
                  printf("wait...\n");
                  sClient = accept(slisten, (SOCKADDR*)&remoteAddr, &nAddrlen);
                  if (sClient == INVALID_SOCKET)
                  {
                      printf("accept error !");
                      continue;
                  }
                  printf("new connect:%d.%d.%d.%d:%d \r\n", remoteAddr.sin_addr.S_un.S_un_b.s_b1, remoteAddr.sin_addr.S_un.S_un_b.s_b2, remoteAddr.sin_addr.S_un.S_un_b.s_b3, remoteAddr.sin_addr.S_un.S_un_b.s_b4, remoteAddr.sin_port);
      
                  //接收数据  
                  int ret = recv(sClient, revData, 255, 0);
                  if (ret > 0)
                  {
                      revData[ret] = 0x00;
                      printf(revData);
                  }
      
                  //发送数据  
                  const char* sendData = "tcp server bak!\n";
                  send(sClient, sendData, strlen(sendData), 0);
                  closesocket(sClient);
                  break;
              }
          }
      
      • 使用客户端连接后,发送 任意数据后 退出
      wait...
      new connect:127.0.0.1:60155
      testes  send from client
      ON_SCOPE_EXIT 释放资源 !
      
  • 相关阅读:
    高效代码编辑器gvim的安装使用和配置
    微机原理与接口技术:数模转换和模数转换 详细笔记
    麒麟v10安装Redis(ARM架构)
    MSDC 4.3 接口规范(24)
    使用python进行数据分析(二)
    mybatis原理及整合spring原理
    如何优雅的创建线程
    spring 请求 出现实体类大小写不一致 出现的问题
    VoLTE基础自学系列 | 什么是VoLTE中的透明数据及非透明数据?
    不抖机灵!让工程师来告诉你做芯片是如何烧钱的!
  • 原文地址:https://blog.csdn.net/jiegemena/article/details/127115136