3

我正在分析代码,但对特定代码感到困惑。我已经发布了将传达相同含义的代码/伪代码。

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 并返回结果集的函数。我已经增强了上面的代码,它更类似于真实的代码。

Collectionobjects 处理 200k 个row对象,正如你们大多数人所说的那样,它们没有正确释放。
调用者在通用 catch 块中看到“未知异常”。这可能是因为在 中创建了巨大的内存泄漏Class 2吗?

我还在日志中看到了一些 Informix 错误406 (Out of memory error)。吐出一系列Unknown Exception&后进程核心转储SQLERR406

我想知道核心转储是否是内存泄漏的副产品。

4

2 回答 2

12

您提供的代码有什么问题?

您提供的代码示例是一个非常糟糕和错误的代码。

没有人删除 (rowclt) 它们中的任何一个。这会导致内存泄漏未定义行为,具体取决于它们的析构函数是否具有微不足道的实现。无论哪种方式,这都意味着可能会发生非常糟糕的事情。

如果使用 分配对象,则new需要通过调用. 由于您没有调用任何一个指针,因此它们都不会被释放。deletenewdelete

谁应该负责删除?

对象本身!
对象应该具有内置功能,可以在它们的范围({})结束后立即解除分配。这样,没有人需要显式释放任何对象,但一旦不再需要它们就会被隐式删除。这种技术在 C++中通常被称为资源分配是初始化 (RAII) 或范围绑定资源管理 (SBRM) 。

您的每个对象(rowclt)都应该通过在这些原始指针上编写包装器来使用RAII,或者更简单地使用现成的智能指针

于 2012-06-20T12:41:20.487 回答
2

智能指针是您所需要的。您应该将每个 newRow放入std::shared_ptr<Row> row而不是指针;当它们超出范围时(例如,当 try-catch 块退出时),这些shared_ptrs 将被自动清理。

你应该用 ' 做什么clt并不是那么明确......我很想将它存储在 a 中std::unique_ptr<Collection>并返回它,因为很明显 a) 它会在某个时候被自动删除(可能在你的程序exits) 和 b) 调用代码很清楚,它们现在拥有由 返回的值get_records_from_db(),而不是Class2生成它的实例(或单例)。

清晰的所有权语义是一件好事。

于 2012-06-20T12:46:56.283 回答