我正在分析代码,我对特定代码感到困惑。 我发布了代码/伪代码,它们将传达相同的含义。
第1课
Class1::Func1()
{
Collection* cltn;
try
{
cltn = Class2::get_records_from_db();
}
catch(Informix error)
{}
catch(DB Error)
{}
catch(...)
{ Unknown exception } //I get this error always once the process processes lot of records
}
第2课
Collection* Class2::get_records_from_db()
{
Collection *clt = new Collection();
try
{
//Query database
For each row in query result
Row *row = new row();
populate(row)
clt->add(*row)
...
if( Informix error)
{
throw Informix error;
}
}
catch(...)
{
delete clt; //Who will delete row?
clt = 0;
throw Db error
}
return clt; //Who will delete clt?
}
问题 - 第2部分
感谢您对第一个问题的见解。现在这是正在发生的真正问题。
Class 1
是一个C ++进程,Class 2
是一个与Informix数据库对话的库。
Class2::get_records_from_db()
是一个查询Informix DB并返回结果集的函数。我已经增强了上面的代码,它更类似于真正的代码。
Collection
个对象会处理200k个row
个对象,正如大多数人所说的那样,这些对象无法正常释放。
调用者在常规catch块中看到“Unknown exception”。可能是因为Class 2
中创建的巨大内存泄漏?
我还在日志中看到一些Informix错误406 (Out of memory error)
。在吐出一系列Unknown Exception
& SQLERR406
我想知道核心转储是否是内存泄漏的副产品。
答案 0 :(得分:12)
您提供的代码有什么问题?
您提供的代码示例是一个非常错误和错误的代码。
没有人删除( row
和clt
)。这会导致 内存泄漏 或 未定义行为 ,具体取决于其析构函数是否具有琐碎或非平凡的实现。这意味着可能会发生非常糟糕的事情。
如果使用new
分配对象,则需要通过在delete
返回的指针上调用new
来显式释放它。由于您没有在任何一个指针上调用delete
,因此它们都不会被释放。
谁应该负责删除?
物品本身!
对象应具有内置功能,以便在其范围({
,}
)结束后立即取消分配。这样,没有人需要显式释放任何对象,但是一旦不再需要它们就会被隐式删除。这种技术在C ++中通常被称为 Resource Allocation is Initialization(RAII) or Scope Bound Resource Management(SBRM) 。
您的每个对象( row
和clt
)都应该使用 RAII ,通过在这些原始指针上编写包装器或者更简单地使用随时可用的 Smart pointers 。
答案 1 :(得分:2)
智能指针是您所需要的。您应该将每个新Row
放入std::shared_ptr<Row> row
而不是指针;那些shared_ptr
将在超出范围时自动清除(例如,当try-catch块退出时)。
你应该对'clt
做些什么并不是那么明确......我很想将它存储在std::unique_ptr<Collection>
中然后返回,因为很明显a)它会在某个时候被自动删除(可能是你的程序退出时)和b)调用代码很明显他们现在拥有get_records_from_db()
返回的值,而不是Class2
实例(或单例)它产生了它。
明确所有权语义是一件好事。