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); // 没有释放
}
```
怎么防止这种没有正常释放资源操作
-
使用
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;
-
使用 智能指针
#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"; // 输出 乱码,已经释放掉 }
-
使用 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 释放资源 !