c++ 资源回收学习

2023-05-16

c++ 资源回收学习

  • c++ 语言的资源回收

使用 delete

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

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

```

#include <iostream>

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 <iostream>
    
    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 <iostream>
    #include <memory>
    
    using namespace std;
    
    int main()
    {
        // shared_ptr<int> tmpi_1(new int);
        // shared_ptr<int> tmpi_1 = make_shared<int>(new int);
        int* check_tmpi_2 = nullptr;
    
        {
            shared_ptr<int> 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<int> 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 <iostream>
    #include <memory>
    
    using namespace std;
    
    
    // --beg ScopeGuard
    #include <functional>
    
    class ScopeGuard
    {
    public:
        explicit ScopeGuard(std::function<void()> onExitScope)
            : onExitScope_(onExitScope), dismissed_(false)
        { }
    
        ~ScopeGuard()
        {
            if (!dismissed_)
            {
                onExitScope_();
            }
        }
    
        void Dismiss()
        {
            dismissed_ = true;
        }
    
    private:
        std::function<void()> 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 <iostream>
    #include <memory>
    
        // --beg ScopeGuard
        #include <functional>
    
        class ScopeGuard
        {
        public:
            explicit ScopeGuard(std::function<void()> onExitScope)
                : onExitScope_(onExitScope), dismissed_(false)
            { }
    
            ~ScopeGuard()
            {
                if (!dismissed_)
                {
                    onExitScope_();
                }
            }
    
            void Dismiss()
            {
                dismissed_ = true;
            }
    
        private:
            std::function<void()> 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 <winsock2.h>  
        #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 释放资源 !
    
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

c++ 资源回收学习 的相关文章

随机推荐

  • Spring+OpenCV+Linux(libopencv_java460.so、opencv-460.jar)人脸识别、人脸对比实现

    准备工作 Linux生成libopencv java460 so opencv 460 jar lbpcascade frontalface xml文件 opencv源码地址 xff1a https github com opencv op
  • net core3.0 修改 web 端口

    修改程序发布之后的端口 新建项目 xff0c 啥都不干启动成功后 xff0c 在 appsettings json 中 添加配置 urls http 8080 34 Logging 34 34 LogLevel 34 34 Default
  • go 语法入门

    go 语法 循环 package main import 34 fmt 34 func main i 61 0 for i lt 1000 i 43 43 fmt Println 34 循环次数 xff1a 34 i 定义局部变量 var
  • windows vscode mingw c++入门(1)

    windows vscode mingw c 43 43 入门 xff08 1 xff09 安装 mingw32 https osdn net projects mingw downloads 68260 mingw get setup e
  • windows vscode mingw c++入门(2)

    windows vscode mingw c 43 43 入门 xff08 2 xff09 导包 新建文件夹 first 与 mian cpp 同级新建文件夹 first新建两个文件q h pragma once 防止重复导入 void q
  • netcore3 sqlite

    net core3 1 EF 43 SQLite nuget 安装这3个包 microsoft EntityFrameworkCore Microsoft EntityFrameworkCore Sqlite Microsoft Entit
  • windows 上 consul

    本机开发模式 consul官网 本机开发者模式 consul exe agent dev 局域网 consul exe agent dev client 0 0 0 0
  • go 通道(channel),go 线程间通信

    go 通道 xff08 channel xff09 是用来传递数据的一个数据结构 通道可用于两个 goroutine 之间通过传递一个指定类型的值来同步运行和通讯 操作符 lt 用于指定通道的方向 xff0c 发送或接收 span clas
  • windows 批量关闭 python 程序工具

    windows 批量关闭 python 程序工具 在windows上启动大量pythonw 后台程序 xff0c 都不知道哪个是哪个 l par query par a show all lk par 终止查询到的程序 python 源码
  • windows+vscode+MinGW+cmake(学习1)

    统一下载 64 位安装 1 安装vscode 官网 安装插件 2 安装 mingw 官网 或者 3 安装cmake 官网 安装好之后 创建 项目文件夹 cmaketest1 创建文件 xff08 1 xff09 main c span cl
  • Springcloud、Springmvc+Nacos注册中心实现服务注册

    目录 背景 实现 Nacos环境搭建 Springcloud服务注册 Maven配置 代码实现 Springmvc服务注册 Maven依赖 代码实现 背景 不管是springcloud还是springmvc实现服务的自动注册 xff0c 都
  • go 并发学习-互斥锁

    go 并发学习 互斥锁 并发输出 inums 自增编写代码运行输出并不能正常输出 使用互斥锁修改代码结果结果正常 使用锁时注意上锁的资源独立函数有些时候用读写锁如果可以改为使用 channel 并发输出 inums 自增 编写代码 pack
  • Ava Trader MT4 Terminal EA交易(1)运行第一个程序

    Ava Trader MT4 Terminal EA交易 xff08 1 xff09 运行第一个程序 1 打开程序化交易编译器 2 文件 新建 下一步 下一步 一直下一步 43 43 11 mq4 Copyright
  • Ava Trader MT4 Terminal 程序化交易(2)获取品种交易数据

    Ava Trader MT4 Terminal 程序化交易 xff08 2 xff09 获取品种交易数据 官方文档 Example 43 43 Script program start function 43
  • Ava Trader MT4 Terminal 程序化交易(3)选择使用那个策略与品种

    Ava Trader MT4 Terminal 程序化交易 xff08 3 xff09 选择使用那个策略与品种 选择品种 右键 打开图表 选择 K线 周期 选择策略 xff0c 长按鼠标左键拉到 图表 xff0c 点击确定 运行中 xff0
  • Ava Trader MT4 Terminal EA交易(4)注册模拟账号,写第一个策略

    注册模拟号 https myvip avatrade cn 策略要求 监控一分钟k线 xff0c 如果连续两根阳线 xff0c 就 做多 设置 10 个点差值的 止盈跟 止损 新建ea模板 first1 代码如下 43 43 first1
  • Golang +vscode 环境搭建

    Golang 环境搭建 Golang 43 vscode 环境搭建1 下载go安装包2 随便创建 gohome 目录3 国内链接谷歌需要代理 xff0c 使用go代理4 在gohome目录创建 src 文件夹5 在first文件夹创建 ma
  • cmake 添加子库

    cmake 添加子库 文件目录 http lib2 testlib CMakeLists txtTest cppTest h CMakeLists txtmain cpp 文件如下 main cpp include lt iostream
  • debian/ubuntu 安装c++开发环境 (2)

    Debian ubuntu 安装c 43 43 开发环境 安装环境 gcc sudo apt get install gcc sudo apt get install make sudo apt get install cmake sudo
  • c++ 资源回收学习

    c 43 43 资源回收学习 c 43 43 语言的资源回收 使用 delete 例子 include lt iostream gt int main int tmpi 61 new int tmpi 61 1 std cout lt lt