是的,你沒有看錯,html
不是c++不是c#,c++
就是你認識的那個c語言。git
在很長一段時間裏,c的內存管理問題,程序員
層出不窮,不是編寫的時候特別費勁繁瑣,github
就是碰到內存泄漏排查的各類困難,c#
特別在多線程環境下,就難上加難了,多線程
諸如此類的老大難問題。app
c++用它的RAII機制妥妥影響了一代程序員。函數
RAII大概介紹下,就不作科普,ui
有須要的同窗,百度一下了解細節。
資源獲取即初始化 (Resource Acquisition Is Initialization, RAII),RAII是一種資源管理機制,資源的有效期與持有資源的對象生命期嚴格綁定,即由對象的構造函數完成資源的分配,由析構函數完成資源的釋放,總結一句話就是 用對象來管理資源
當一個對象離開做用域的時候就會被釋放,會調用這個對象類的析構函數,這都是自動管理的,不須要咱們手動調用。因此咱們能夠把資源封裝到類的內部,當須要用資源的時候初始化對象便可,當對象被釋放的時候資源也會被釋放
當你寫了多年c代碼,你是多麼渴望有這麼一個東西能夠給到你。
衆望所歸,終於gcc編譯器開了個小竈,留了一個後門造福c程序員。
詳情見:
https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html
主要看這個:
cleanup (cleanup_function)
The cleanup attribute runs a function when the variable goes out of scope. This attribute can only be applied to auto function scope variables; it may not be applied to parameters or variables with static storage duration. The function must take one parameter, a pointer to a type compatible with the variable. The return value of the function (if any) is ignored.
If -fexceptions is enabled, then cleanup_function is run during the stack unwinding that happens during the processing of the exception. Note that the cleanup attribute does not allow the exception to be caught, only to perform an action. It is undefined what happens if cleanup_function does not return normally.
這個cleanup機制,用起來,妥妥就是一個c的析構函數了。
沒有必要造輪子,輪子已經造好了。
libcsptr提供了經常使用智能指針的封裝,
unique_ptr, shared_ptr ,絕對是夠用了。
項目地址:
https://github.com/Snaipe/libcsptr
花了點小時間編寫示例代碼,造福你們。
順手解決vs的編譯問題。
另外說一下,vs不是gcc,沒有cleanup 能夠實現這個功能。
不過能夠經過安裝llvm在vs裏選擇llvm編譯進行編譯。
到https://llvm.org/releases/download.html
下載後安裝,再啓動vs就能夠看到編譯器選項了。
貼個圖上來,可參照一下。
選好以後,就能夠玩起來一些clang特性了。
完整示例代碼:
#include <stdio.h> #include "csptr_smart_ptr.h" struct BufferBody { char *buffer; size_t size; }; static void callback_dtor(void *ptr, void *meta) { (void) meta; struct BufferBody *ctx = ptr; if (ctx->buffer != NULL) free(ctx->buffer); } struct BufferBody *write_buffer(const char *bufbody, size_t init_body_len) { smart struct BufferBody *ctx = shared_ptr(struct BufferBody, { 0 }, callback_dtor); if (!ctx) // failure to allocate return NULL; // nothing happens, destructor is not called if (ctx->buffer == NULL) { ctx->buffer = malloc(init_body_len); if (ctx->buffer != NULL) ctx->size = init_body_len; } else { if (ctx->size < init_body_len) { ctx->buffer = realloc(ctx->buffer, init_body_len); if (ctx->buffer != NULL) ctx->size = init_body_len; } } size_t buflen = strlen(bufbody); if (ctx->size > buflen) memcpy(ctx->buffer, bufbody, buflen); return sref(ctx); // a new reference on bufCtx is returned, it does not get destoyed } void do_something(size_t init_body_len) { smart struct BufferBody *ctx = write_buffer("hello smart ptr.", init_body_len); printf("%s \n", ctx->buffer); // ctx is destroyed here } int main(void) { printf("Smart pointers for the (GNU) C\n"); printf("blog: http://cpuimage.cnblogs.com/\n"); printf("tips: u can use llvm to compile in visual studio"); printf("download llvm: http://releases.llvm.org/download.html"); // some_int is an unique_ptr to an int with a value of 1. smart int *some_int = unique_ptr(int, 1); printf("%p = %d\n", some_int, *some_int); size_t init_body_len = 4096; do_something(init_body_len); // some_int is destroyed here return 0; }
很是簡單,代碼嚴謹性不深究,你們看下示例的具體用法就能夠了。
我都以爲簡單得寫註釋都有點多餘。
因爲原項目文件挺多的,編譯挺麻煩的。
就操刀簡單修改了一下,
主要是將代碼合爲一個文件csptr_smart_ptr.h,附示例代碼,乾淨便攜。
對應項目地址:
https://github.com/cpuimage/libcsptr
只能說,有了它,你能夠省下很多c內存管理心了。
固然會有不少人質疑說,會不會有大坑,
也許會有,也許沒有,可是c智能指針的確能夠有。
我比較相信事實,固然事實就是編譯器提供了一個路子給你,
然而有些人確實可能會說,不相信編譯器,
嗯,對的,我也不信。
可是,毫無疑問,你們雖然不信可是都在用。
嘴上那樣說,身體仍是很誠實的。
以上,權當拋磚引玉。
獨樂樂不如一塊兒玩樂。
如有其餘相關問題或者需求也能夠郵件聯繫俺探討。
郵箱地址是: gaozhihan@vip.qq.com