C的智能指针/安全内存管理?

man*_*ken 43 c memory pointers smart-pointers c99

我和其他许多人一样,使用智能指针在C++中包含不安全的内存操作,使用RAII等等,已经取得了巨大的成功.但是,当您具有析构函数,类,运算符重载等时,包装内存管理更容易实现.

对于使用原始C99编写的人,您可以在哪里指出(没有双关语)来帮助安全内存管理?

谢谢.

Sna*_*ipe 20

问题有点旧,但我想我会花时间链接到GNU编译器的智能指针库(GCC,Clang,ICC,MinGW,...).

此实现依赖于清理变量属性(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;
}
Run Code Online (Sandbox Code Playgroud)

编译和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)
Run Code Online (Sandbox Code Playgroud)


Ree*_*sey 13

在原始C中处理智能指针很困难,因为您没有语言语法来备份使用情况.我见过的大多数尝试都没有真正起作用,因为当对象离开范围时,你没有运行析构函数的优势,这正是使智能指针工作的原因.

如果您真的担心这一点,您可能需要考虑直接使用垃圾收集器,并完全绕过智能指针要求.

  • 垃圾收集器链接已损坏。 (2认同)

D.S*_*ley 8

您可能想要考虑的另一种方法是Apache使用的池化内存方法.如果您具有与请求或其他短期对象关联的动态内存使用情况,则此方法非常有效.您可以在请求结构中创建一个池,并确保始终从池中分配内存,然后在处理完请求后释放池.它听起来并不像你曾经使用它一样强大.它几乎和RAII一样好.


Cal*_*ius 5

你不能在 C 中做智能指针,因为它没有提供必要的语法,但你可以通过练习避免泄漏。分配后立即编写资源释放代码。因此,无论何时编写 a malloc,都应free立即在清理部分中编写相应的内容。

在 CI 中经常看到“GOTO 清理”模式:

int foo()
{
    int *resource = malloc(1000);
    int retVal = 0;
    //...
    if (time_to_exit())
    {
        retVal = 123;
        goto cleanup;
    }
cleanup:
    free(resource);
    return retVal;
}
Run Code Online (Sandbox Code Playgroud)

在 C 中,我们也使用了很多分配内容的上下文,同样的规则也可以应用于:

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);
}
Run Code Online (Sandbox Code Playgroud)

这类似于对象构造函数和析构函数。只要您不将分配的资源分配给其他对象,它就不会泄漏,指针也不会悬垂。

编写一个自定义分配器来跟踪分配并写入泄漏块并不困难atexit

如果您需要放弃指向已分配资源的指针,您可以为其创建包装上下文,并且每个对象拥有一个包装上下文而不是资源。这些包装器共享资源和一个计数器对象,该对象跟踪使用情况并在没有人使用时释放对象。这就是C ++ 11级的shared_ptrweak_ptr作品。这里有更详细的描述:weak_ptr 是如何工作的?