C를 위한 스마트 포인터/안전한 메모리 관리
저나 다른 많은 사람들은 스마트 포인터를 사용하여 안전하지 않은 메모리 작업을 C++로 정리하고 RAII 등을 사용하여 큰 성공을 거뒀다고 생각합니다.단, 랩 메모리 관리는 디스트럭터, 클래스, 연산자 오버로드 등이 있는 경우 구현이 용이합니다.
raw C99로 글을 쓰는 사람에게 안전한 메모리 관리에 도움이 되는 (말장난 의도가 없는) 장소를 알려주실 수 있습니까?
고마워요.
질문이 좀 오래되었지만 GNU 컴파일러용 스마트 포인터 라이브러리(GCC, Clang, ICC, MinGW 등)에 링크하는 데 시간을 할애해야겠다고 생각했습니다.
이 실장은 범위를 벗어나면 메모리를 자동으로 해방시키기 위해 Cleanup variable 속성인 GNU 확장에 의존합니다.따라서 ISO C99가 아니라 GNU 확장이 있는 C99입니다.
예:
심플1.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;
}
컴파일 및 밸린더 세션:
$ 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)
자, 여기 선택사항이 있습니다.이상적으로는 더 나은 결과를 얻기 위해 이들을 결합하는 것입니다.C의 경우 편집증도 괜찮습니다.
컴파일 시간:
- GCC에서 cleanup variable Atribute를 사용합니다.그 이후에는 GCC를 고수해야 합니다.GCC가 존재하는 플랫폼만 대상으로 할 수 있기 때문에 코드 이식성이 제한됩니다.
- Windows 에서는 SEH(구조화된 예외 처리)를 사용합니다.Microsoft 컴파일러를 사용해야 하므로 휴대성이 더욱 제한됩니다.타겟이 Windows 전용인 경우는, 유효합니다.
- 메모리 누수 가능성을 나타내는 정적 코드 분석 도구를 사용합니다.완벽하게 작동하지는 않지만 사소한 누출을 찾는데 도움이 될 수 있습니다.휴대성에는 영향을 주지 않습니다.
실행 시:
- malloc/free를 자체 구현으로 대체하고 메모리 사용량을 추적하는 디버깅메모리 할당 라이브러리를 사용합니다.이렇게 하면 할당되었지만 해제되지 않은 블록을 볼 수 있습니다.Solaris 용으로 성공했습니다(이름을 기억해 보겠습니다).
- 가비지 콜렉터를 사용합니다.소스 코드가 없는 누출이 심한 C 어플리케이션을 수정하면서 Hans-Boehm GC에서 좋은 경험을 했습니다.메모리 소비량이 얼마나 증가하는지 알 수 있었는데 GC가 작동하자 메모리 소비량이 급감했습니다.
C에서는 필요한 구문을 제공하지 않기 때문에 스마트포인터를 실행할 수 없지만 실천을 통해 누수를 방지할 수 있습니다.리소스 릴리스 코드를 할당한 직후에 작성합니다. 이 글을 쓸 malloc
그럼 여기에 하는 것을 합니다.free
바로 청소 구역에서요
C에서는 'GOTO cleanup' 패턴이 많이 보입니다.
int foo()
{
int *resource = malloc(1000);
int retVal = 0;
//...
if (time_to_exit())
{
retVal = 123;
goto cleanup;
}
cleanup:
free(resource);
return retVal;
}
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);
}
이는 객체 생성자 및 소멸자와 유사합니다.할당된 리소스를 다른 개체에 할당하지 않는 한 해당 리소스는 유출되지 않으며 포인터도 중단되지 않습니다.
블록을 않습니다.atexit
.
할당된 리소스에 대한 포인터가 필요한 경우 해당 리소스에 대한 래퍼 컨텍스트를 생성할 수 있으며 각 개체는 리소스 대신 래퍼 컨텍스트를 소유합니다.이러한 래퍼는 리소스와 카운터 개체를 공유합니다.이러한 개체는 사용량을 추적하여 아무도 사용하지 않을 때 개체를 해방합니다.의 C++11은 이렇게 .shared_ptr
★★★★★★★★★★★★★★★★★」weak_ptr
효과가 있습니다. 자세한 내용은 여기에 기재되어 있습니다.weak_ptr의 구조
raw C에서는 사용을 백업하는 언어 구문이 없기 때문에 스마트 포인터를 처리하기가 어렵습니다.지금까지 본 대부분의 시도는 효과가 없습니다.왜냐하면 오브젝트가 스코프를 벗어날 때 디스트럭터가 실행된다는 장점이 없기 때문입니다.그것이 스마트 포인터를 유효하게 하는 것입니다.
이 문제가 정말로 우려되는 경우 가비지 컬렉터를 직접 사용하여 스마트 포인터 요구 사항을 모두 우회하는 것을 고려해 볼 수 있습니다.
Apache에서 사용하는 풀링 메모리 접근 방식도 고려할 수 있습니다.이는 요청 또는 기타 단시간 개체와 관련된 동적 메모리 사용량이 있는 경우 특히 잘 작동합니다.요청 구조에 풀을 생성하여 항상 풀에서 메모리를 할당하고 요청 처리가 완료되면 풀을 해방할 수 있습니다.조금 사용해보니 파워가 떨어지는 것 같아요.그것은 거의 RAII만큼 좋다.
BEGIN 및 END 등의 매크로를 정의하여 괄호 대신 사용할 수 있으며 해당 범위를 벗어나는 리소스의 자동 파괴를 트리거할 수 있습니다.이를 위해서는 이러한 모든 리소스가 오브젝트의 소멸자에 대한 포인터를 포함하는 스마트 포인터에 의해 지시되어야 합니다.실장에서는 스마트포인터 스택을 힙메모리에 보관하고 스코프 엔트리 스택포인터를 기억하고 스코프 출구 시 기억된 스택포인터 위에 있는 모든 자원의 디스트럭터를 호출합니다(반환용 END 또는 매크로 치환).이는 setjmp/longjmp 예외 메커니즘을 사용하는 경우에도 정상적으로 동작하며 catch-block과 예외가 발생한 범위 사이의 모든 중간 범위도 청소합니다.실장에 대해서는, https://github.com/psevon/exceptions-and-raii-in-c.git 를 참조해 주세요.
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 !
*/
부목이나 Gimpel PC-Lint와 같은 정적 코드 분석 툴이 도움이 될 수 있습니다.또, 그것들을 자동 「연속 통합」스타일의 빌드 서버에 배선하는 것으로, 적당히 「예방적」으로 할 수도 있습니다(이것들 중 하나가 있습니까?: 라이선스:)
이 테마에는 다른 (더 비싼) 변종도 있습니다.
언급URL : https://stackoverflow.com/questions/799825/smart-pointers-safe-memory-management-for-c
'source' 카테고리의 다른 글
gcc 프리프로세서 출력에서 해시 기호와 #1 "a.c"와 같은 숫자로 시작하는 행의 의미는 무엇입니까? (0) | 2022.08.19 |
---|---|
모바일 장치에서 네비게이션 바를 mini로 전환 (0) | 2022.08.19 |
Java 재귀 피보나치 시퀀스 (0) | 2022.08.19 |
Vue.js 및 jQuery? (0) | 2022.08.19 |
Signal R을 Vue.js 및 Vuex와 통합 (0) | 2022.08.19 |