2013-07-29 3 views
6

이 질문이 중복되는 경우 사과드립니다. 잠시 동안 수색했으나 내 Google-fu가 스너프가 아닐 가능성이 있습니다.C++에서 예외가 throw 된 후 메모리를 어떻게 해제해야합니까?

C 라이브러리를 호출하는 C++ 프로그램을 수정 중입니다. C 라이브러리는 (malloc()을 사용하여) 메모리를 할당하고 C++ 프로그램은이를 사용하고 해제합니다. catch는 C++ 프로그램이 실행 중간에 예외를 throw하여 할당 된 메모리가 절대로 해제되지 않도록합니다.

/* old_library.c */ 
char *allocate_lots() { 
    char *mem = (char *)malloc(1024); 
    return mem; 
} 

/* my_prog.cpp */ 
void my_class::my_func() { 
    char *mem = allocate_lots(); 
    bool problem = use(mem); 
    if (problem) 
     throw my_exception("Oh noes! This will be caught higher up"); 
    free(mem); // Never gets called if problem is true 
} 

내 질문은 다음과 같습니다 :이 다루는 마땅 방법 (오히려 인위적인) 예를 들어

? 내 첫 번째 아이디어는 시도/catch 블록에서 모든 것을 래핑하는 것이 었습니다. catch를 그냥 확인하고 메모리를 비우고 예외를 다시 던지기 만했습니다.하지만 이것은 나에게 무섭고 어설픈 것처럼 보입니다. 실제로는 예외를 잡으려고합니다. 그것을 할 수있는 더 좋은 방법이 있습니까?

편집 : std :: unique_ptr가 도입되기 전에 2007 년에 g ++ 4.2.2를 사용했음을 언급 했어야합니다. 기업의 관성에 맞추어 말하십시오.

+1

왜 예외를 throw하기 전에 메모리를 비울 수 없습니까? –

+13

RAII를 사용하여 문제를 해결했습니다. – Borgleader

답변

7

무료 통화 사용자 정의 Deleter가 함께 사용할 수 std::unique_ptr :

class free_mem { 
public: 
    void operator()(char *mem) { free(mem); } 
}; 

void my_class::my_func() { 
    std::unique_ptr<char, free_mem> mem = allocate_lots(); 
+0

이것은 우리가 g ++의 이전 버전을 사용하고 있다는 것을 제외하고는 아마도 옳은 대답 일 것입니다 (위의 편집 참조). – Dan

+6

자신 만의 unique_ptr 대체품을 작성한 후 상사에게 왜 2 일 동안 무료로 기본 언어 도구를 디버깅하여 업그레이드가 가능했는지 설명하십시오. 업그레이드하는 데 걸리는 시간에 비해 오래된 도구로 낭비되는 시간에 가중치를 둘 때까지 반복하십시오. – DanielKO

4

당신은 당신이 메모리 해제가 완료 될 때까지 포기하지 있는지 확인한다 - 또는 당신의 mem를 저장하는 데 적합한 스마트 포인터 구조를 사용하도록 그 throw이 발생하고, 스택은 mem 풀릴 때 해방된다.

1

if 절의 메모리를 해제하지 않는 이유가 있습니까?

if (problem) { 
    free (mem); 
    throw my_exception ("Drat!"); 
} 
+6

코드 복제,이 특별한 경우에는 '자유'가 실제로 조건부로 이동되기 전에 가능합니다. 장기적으로 누군가가 여기에서 벌어지고있는 일을 모른다고해서 깨지기 쉬운 자원을 다루지 않고 던질 수있는 또 다른 기능으로 또 다른 '던지기'또는 '돌아 가기'또는 호출을 삽입 할 수있는 위험이 있습니다. RAII는 멍청한 다음 사람을 보호합니다. – Casey

4

랩이 장난 꾸러기 :

struct malloc_deleter { 
    template <typename T> 
    void operator() (T* p) const { 
    free(p); 
    } 
}; 

void my_class::my_func() { 
    std::unique_ptr<char[],malloc_deleter> mem{allocate_lots()}; 
    bool problem = use(mem.get()); 
    if (problem) 
     throw my_exception("Oh noes! This will be caught higher up"); 
} 
+0

음. 'char []'의 사용법을 설명 할 수 있습니까? – sehe

+0

'unique_ptr '는'operator ->'대신에'operator []'을 오버로딩하고 기본적으로'delete []'를 사용하는 부분적 전문화입니다 (여기서 중요한 것은 아님). – Casey

+0

나는 그때와 영원히 혼돈 스럽다. 나는'shared_ptr'이 그것을 가지고 있다고 생각했다. 하지만 분명히, 그들은 shared_ptr에 같은 것을 더하는 걸 잊었습니다. – sehe

1

사용 unique_ptr : http://coliru.stacked-crooked.com/view?id=cd3f0fc64d99cc07a2350e2ff9686500-542192d2d8aca3c820c7acc656fa0c68

#include <stdexcept> 
#include <iostream> 

#include <memory> 

/* old_library.c */ 
char *allocate_lots() 
{ 
    return static_cast<char*>(malloc(1024)); 
} 

struct my_exception : virtual std::exception { 
    const char* const msg; 
    my_exception(const char* const msg) : msg(msg) {} 
    const char* what() const noexcept { return msg; } 
}; 

struct my_class 
{ 
    struct Free { void operator() (char* p) const { free(p); } }; 
    /* my_prog.cpp */ 
    void my_func() 
    { 
     std::unique_ptr<char, Free> mem; 

     mem.reset(allocate_lots()); 
     bool problem = use(mem.get()); 

     if(problem) 
     { 
      throw my_exception("Oh noes! This will be caught higher up"); 
     } 
    } 

    static bool use(char*) { return true; } 
}; 

int main() 
{ 
    my_class prog; 
    prog.my_func(); 
} 
+2

@Dan은'unique_ptr'을''boost :: scoped_ptr' '(http://www.boost.org/doc/libs/1_54_0/libs/smart_ptr/scoped_ptr.htm)로 바꾸십시오. 가지고 있지 않다면 – sehe

2

Y부터 unique_ptr이없는 이전 컴파일러 버전을 사용 ou're, 당신은 당신의 RAII 자신 래퍼 작성할 수 있습니다

class ResourceWrapper { 
public: 
    ResourceWrapper(char* ptr) : m_ptr(ptr) {} 
    ~ResourceWrapper() { free(m_ptr); } 
    // whatever getters suit you, at the very least: 
    char* get() const { return m_ptr; } 
private: 
    char* const m_ptr; 
}; 

void my_class::my_func() { 
    ResourceWrapper mem(allocate_lots()); 
    bool problem = use(mem.get()); 
    if (problem) 
     throw my_exception("Oh noes! This will be caught higher up"); 
} 

그냥 심지어 암시 복사/할당을 할 수 있도록해야합니다 하지을 (내가 m_ptr을 만든 이유입니다 const) 또는 메모리를 두 배로 늘릴 위험이 있습니다 (이 절대적으로 일 때까지 "이동"의미 (auto_ptr)을 피하는 것이 가장 좋습니다.

2

std::unique_ptr을 사용할 수 없으므로 RAII 방식으로 포인터의 수명을 제어하는 ​​자체 Deleter 클래스를 만들 수 있습니다. 간단하게하기 위해이 예제는 실제 포인터를 감싸지는 않지만 실제 포인터와 나란히 존재합니다. 보다 안전한 접근 방법은 진정한 스마트 포인터 클래스를 만드는 것입니다.

class AutoFree 
{ 
public: 
    AutoFree(void* p) : m_p(p) 
    { 
    } 
    ~AutoFree() 
    { 
     free(m_p); 
    } 
private: 
    void* m_p; 
}; 

void my_class::my_func() { 
    char *mem = allocate_lots(); 
    AutoFree mem_free(mem); 
    bool problem = use(mem); 
    if (problem) 
     throw my_exception("Oh noes! This will be caught higher up"); 
} 
+0

으로 표시하십시오. 실행 중 : http://ideone.com/iLgXdY –

관련 문제