Exception 在C+中引发异常后,如何释放内存+;?

Exception 在C+中引发异常后,如何释放内存+;?,exception,memory,malloc,c++03,Exception,Memory,Malloc,C++03,我很抱歉,如果这个问题是重复的-我搜索了一段时间,但有可能我的谷歌fu不符合要求 >我正在修改一个C++程序,该程序调用C库。C库分配一堆内存(使用 MARROCURE()/COD>),C++程序使用它,然后释放它。问题在于C++程序可以在执行过程中途抛出异常,导致分配的内存永远不会被释放。 作为一个(相当做作的)例子: /*old_library.c*/ char*分配_批次(){ char*mem=(char*)malloc(1024); 返回mem; } /*my_prog.cpp*/ v

我很抱歉,如果这个问题是重复的-我搜索了一段时间,但有可能我的谷歌fu不符合要求

>我正在修改一个C++程序,该程序调用C库。C库分配一堆内存(使用<代码> MARROCURE()/COD>),C++程序使用它,然后释放它。问题在于C++程序可以在执行过程中途抛出异常,导致分配的内存永远不会被释放。 作为一个(相当做作的)例子:

/*old_library.c*/
char*分配_批次(){
char*mem=(char*)malloc(1024);
返回mem;
}
/*my_prog.cpp*/
void my_类::my_func(){
char*mem=allocate_lots();
布尔问题=使用(mem);
如果(问题)
抛出我的例外(“哦,不!这将被更高级别的人抓住”);
free(mem);//如果问题为真,则永远不会调用
}
我的问题是:我应该如何处理?我的第一个想法是将整个过程包装在一个try/catch块中,在catch中只需检查并释放内存并重新抛出异常,但这对我来说似乎既不优雅又笨拙(如果我真的想捕获异常,这将无法正常工作)。有更好的方法吗


编辑:我可能应该提到,我们使用的是g++4.2.2,早在2007年引入std::unique_ptr之前。将其归为公司惯性。

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

有什么理由不简单地释放if子句中的内存吗

if (problem) {
    free (mem);
    throw my_exception ("Drat!");
}
把那个流氓包起来:

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");
}
struct malloc\u deleter{
模板
void运算符()(T*p)常量{
自由基(p);
}
};
void my_类::my_func(){
std::unique_ptr mem{allocate_lots()};
bool problem=use(mem.get());
如果(问题)
抛出我的例外(“哦,不!这将被更高级别的人抓住”);
}

std::unique\u ptr
与调用free的自定义删除程序一起使用:

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

void my_class::my_func() {
    std::unique_ptr<char, free_mem> mem = allocate_lots();
class-free\u-mem{
公众:
void运算符()(char*mem){free(mem);}
};
作废my_类::my_func(){
std::unique_ptr mem=allocate_lots();
使用唯一\u ptr:

#包括
#包括
#包括
/*旧图书馆*/
char*分配_批次()
{
返回静态_cast(malloc(1024));
}
结构my_异常:虚拟std::异常{
常量字符*常量消息;
my_异常(const char*const msg):msg(msg){}
const char*what()const noexcept{return msg;}
};
构造my_类
{
无结构的{void操作符()(char*p)常量{Free(p);};
/*my_prog.cpp*/
作废我的_func()
{
std::唯一的ptr mem;
内存重置(分配批次());
bool problem=use(mem.get());
如果(问题)
{
抛出我的例外(“哦,不!这将被更高级别的人抓住”);
}
}
静态bool用法(char*){return true;}
};
int main()
{
我的班级进步;
prog.my_func();
}

由于您使用的是一个没有唯一性的旧编译器版本,您可以自己编写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),否则你可能会冒着双倍释放内存的风险(“移动”语义a la
auto_ptr
最好避免,除非你绝对需要它).

由于您不能使用
std::unique\u ptr
,您可以创建自己的deleter类,该类将以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");
}

为什么不能在抛出异常之前释放内存?使用RAII,问题已解决。代码复制,尽管在这种特定情况下,
free
确实可以在条件之前移动。长期来看,存在一种危险,即不知道这里发生了什么的人可能会插入另一个
throw
return
或调用另一个可以在不处理脆弱资源的情况下抛出的函数。RAII可以防止下一个家伙变得愚蠢。Mmm。你能解释一下
char[]
的用法吗?
unique\u ptr
是一种局部专门化,它重载
操作符[]
而不是
操作符->
,并使用
delete[]默认情况下(这里显然不重要)。我一直对此感到困惑。我以为
shared\u ptr
有这个功能。但显然,他们忘了为
shared\u ptr
添加相同的功能。正确。
boost::shared\u ptr
有一个
T[]
专门化,但它是在TR1中的标准化之后添加的
shared_ptr
(参见)。这可能是正确的答案,除了我们使用的是旧版本的g++(参见上面的编辑)。这可能是正确的答案,除了我们使用的是旧版本的g++(参见上面的编辑)。编写您自己独特的\u ptr替换,然后向上司解释为什么您花了2天时间调试一个基本语言工具,如果他们允许升级,您将免费获得该工具。重复这一过程,直到他们开始将过时工具所浪费的时间与升级所花费的时间进行加权。@Dan如果您没有,则替换
unique\u ptr
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");
}