c++ 资源回收学习

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 释放资源 !
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值