在C ++中抛出异常后应该如何释放内存?

时间:2013-07-29 21:16:20

标签: exception memory malloc c++03

如果这个问题是重复的,我道歉 - 我搜索了一段时间,但我的Google-fu可能不适合鼻烟。

我正在修改一个调用C库的C ++程序。 C库分配一堆内存(使用malloc()),C ++程序使用它然后释放它。问题是C ++程序可以在执行过程中抛出异常,导致分配的内存永远不会被释放。

作为一个(相当做作的)例子:

/* 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
}

我的问题是:我应该怎么处理这个问题?我的第一个想法是将整个事物包装在一个try / catch块中,并且在catch中只需检查并释放内存并重新抛出异常,但这对我来说似乎没有优点和笨重(如果我不顺利的话)希望实际上捕获异常)。有没有更好的方法呢?

编辑:我可能应该提到我们正在使用g ++ 4.2.2,从2007年开始使用std :: unique_ptr之前。将其归结为企业惯性。

7 个答案:

答案 0 :(得分:8)

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();

答案 1 :(得分:4)

你应该确保在释放内存之前不要抛出 - 或者你使用合适的智能指针结构来存储mem,这样当throw发生时,并且堆栈展开,mem被释放。

答案 2 :(得分: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");
}

答案 3 :(得分:2)

由于您使用的是没有unique_ptr的旧编译器版本,因此您可以自己编写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),或者你冒着双重释放内存的风险(“移动”除非你绝对需要它,否则最好避免使用语义àlaauto_ptr

答案 4 :(得分:2)

由于您无法使用std::unique_ptr,您可以创建自己的删除器类,以RAII方式控制指针的生命周期。为了简单起见,这个例子不包装实际的指针,而是存在于它旁边;一种更安全的方法是制作一个真正的智能指针类。

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");
}

答案 5 :(得分:1)

有没有理由不简单地释放if子句中的内存?

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

答案 6 :(得分: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();
}