我认为许多人都通过使用智能指针成功地封装了C ++中不安全的内存操作,例如RAII等。但是,在没有析构函数,类,运算符重载等情况下实现内存管理更加困难。
对于在裸露的C99中编写代码的人,您可以从哪里获得有关安全内存管理的帮助?
谢谢。
我认为许多人都通过使用智能指针成功地封装了C ++中不安全的内存操作,例如RAII等。但是,在没有析构函数,类,运算符重载等情况下实现内存管理更加困难。
对于在裸露的C99中编写代码的人,您可以从哪里获得有关安全内存管理的帮助?
谢谢。
这个问题有点老了,但我觉得我可以花时间为大家提供我的智能指针库,适用于GNU编译器(GCC、Clang、ICC、MinGW等)。
该实现依赖于cleanup变量属性,这是GNU扩展中的一种,可在作用域结束时自动释放内存,因此它不是ISO C99,而是带有GNU扩展的C99。
示例:
simple1.c:
#include <stdio.h>
#include <csptr/smart_ptr.h>
int main(void) {
smart int *some_int = unique_ptr(int, 1);
printf("%p = %d\n", some_int, *some_int);
// some_int is destroyed here
return 0;
}
编译和Valgrind会话:
$ gcc -std=gnu99 -o simple1 simple1.c -lcsptr
$ valgrind ./simple1
==3407== Memcheck, a memory error detector
==3407== Copyright (C) 2002-2013, and GNU GPL\'d, by Julian Seward et al.
==3407== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info
==3407== Command: ./simple1
==3407==
0x53db068 = 1
==3407==
==3407== HEAP SUMMARY:
==3407== in use at exit: 0 bytes in 0 blocks
==3407== total heap usage: 1 allocs, 1 frees, 48 bytes allocated
==3407==
==3407== All heap blocks were freed -- no leaks are possible
==3407==
==3407== For counts of detected and suppressed errors, rerun with: -v
==3407== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
你可能想要考虑的另一种方法是池内存的方法,这也是Apache使用的方法。如果你需要使用与请求或其他短暂对象相关联的动态内存使用,那么这种方法非常有效。你可以在请求结构中创建一个池,并确保总是从该池中分配内存,然后在处理完请求后释放该池。一旦你使用过它,就会发现它比表面上看起来的强大多了。它几乎和RAII一样好用。
malloc
,就应该立即在清理部分中编写相应的 free
。int foo()
{
int *resource = malloc(1000);
int retVal = 0;
//...
if (time_to_exit())
{
retVal = 123;
goto cleanup;
}
cleanup:
free(resource);
return retVal;
}
int initializeStuff(Stuff *stuff)
{
stuff->resource = malloc(sizeof(Resource));
if (!stuff->resource)
{
return -1; ///< Fail.
}
return 0; ///< Success.
}
void cleanupStuff(Stuff *stuff)
{
free(stuff->resource);
}
如果您正在编写 Win32 程序,您可能可以使用结构化异常处理来实现类似的功能。您可以尝试以下代码:
foo() {
myType pFoo = 0;
__try
{
pFoo = malloc(sizeof myType);
// do some stuff
}
__finally
{
free pFoo;
}
}
虽然不像RAII那样简单,但你可以将所有的清理代码收集到一个地方,并保证它被执行。
Sometimes i use this approach and it seems good :)
Object *construct(type arg, ...){
Object *__local = malloc(sizeof(Object));
if(!__local)
return NULL;
__local->prop_a = arg;
/* blah blah */
} // constructor
void destruct(Object *__this){
if(__this->prop_a)free(this->prop_a);
if(__this->prop_b)free(this->prop_b);
} // destructor
Object *o = __construct(200);
if(o != NULL)
;;
// use
destruct(o);
/*
done !
*/