如果这个问题是重复的,我道歉 - 我搜索了一段时间,但我的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之前。将其归结为企业惯性。
答案 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();
}