2012-06-20 3 views
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 - это процесс на С ++, а Class 2 - это библиотека, которая ведет переговоры с базой данных Informix. Class2::get_records_from_db() - это функция, которая запрашивает базу данных Informix и возвращает результат. Я улучшил код выше, который больше похож на реальный код.

Collection Объекты имеют дело с 200k объектов row, которые, как большинство из вас сказали, не выпущены должным образом.
Звонящий видит «Неизвестное исключение» в общем блоке catch. Может ли это быть из-за огромных утечек памяти, созданных в Class 2?

Я также вижу некоторые ошибки Informix 406 (Out of memory error) в журналах. Процесс ядро-отвалы после выплевывая серию Unknown Exception & SQLERR406

Я хочу знать дамп, является ли побочный продукт из утечек памяти.

+0

Если код действительно является тем, что вы показываете, есть утечки памяти. –

+0

В 'get_records_from_db' переменная' row' обязательно должна быть удалена внутри 'catch'. Кроме того, поскольку 'clt' возвращается, должно быть установлено' NULL' внутри 'catch' или будет висящий указатель. После того, как функция вернется, ответственность за удаление возвращаемой выделенной памяти, по моему мнению, должна быть ответственной. Однако он должен быть хорошо документирован, чтобы пользователь API знал об этом. –

+1

-1 запрашивает ответственность за освобождение и ** не документирует тип возврата **. –

ответ

12

В чем проблема с кодом, который вы указали?

Пример кода, который вы представляете, является очень плохим и неправильным кодом.

Никто не удаляет ни один из (row и clt) их. Это приводит к памяти утечка или Неопределенного поведение в зависимости от того, их деструкторов имеют тривиальный или нетривиальный путь implementation.Either это означает очень плохие вещи могут случиться.

Если вы выделили объект, используя new, вам необходимо явно освободить его, вызвав delete по указателю, возвращенному new. Поскольку вы не вызываете delete на любом из указателей, они оба не освобождаются вообще.

Кому следует отвечать за удаление?

Объекты сами!
Объекты должны иметь встроенную функциональность, чтобы де-выделить себя, как только их объем ({, }) заканчивается. Таким образом, никто не должен явно освобождать какой-либо из объектов, но они неявно удаляются, как только они больше не нужны. Этот метод широко известен как Resource Allocation is Initialization(RAII) or Scope Bound Resource Management(SBRM) в C++.

Каждые из ваших объектов (row и clt) должен использовать RAII написав обертки над этими сырыми указателями или даже лучше просто с помощью легкодоступного Smart pointers.

+0

Почему это ведет к UB? – Nawaz

+0

@Nawaz: C++ 11 3.8 Время жизни объекта, параграф 4: * ".... однако, если нет явного вызова деструктора или если выражение удаления (5.3.5) не используется для освобождения хранилища , деструктор не должен быть неявно вызван, и любая программа, зависящая от побочных эффектов, созданных деструктором, имеет неопределенное поведение ». * Поэтому мой ответ говорит *« в зависимости от того, имеют ли их деструкторы тривиальную или нетривиальную реализацию ». * –

+0

@Als - Спасибо за понимание. Я обновил свою проблему. – cppcoder

2

Умные указатели - это то, что вам нужно. Вы должны поместить каждый новый в std::shared_ptr<Row> row вместо указателя; те shared_ptr s будут автоматически очищены, когда они выйдут из области видимости (например, когда выйдет блок try-catch).

Что вы должны делать с 'clt, это не совсем так понятно. Я бы захотел сохранить его в std::unique_ptr<Collection> и вернуть его, потому что тогда ясно, что а) оно будет автоматически удалено на некоторых (возможно, когда ваша программа выйдет), и b) ясно, что код вызова теперь имеет значение, возвращаемое get_records_from_db(), а не экземпляр Class2 (или singleton), сгенерировавший его.

Четкая семантика собственности - это хорошо.

Смежные вопросы