2012-03-28 2 views
0

Я выделяю память для объекта, и если какой-то конкретный оператор, следующий за распределением памяти, терпит неудачу, я должен удалить память, а также выбросить исключение.C++ programming try catch

Например сказать

   QSqlQuery *query = new QSqlQuery(db); 
       try { 
       query->prepare(somestmt); 
       } 
       catch (...) { 
       throwException(*query); 
       } 

Вот где и как я должен удалить запрос, если исключение?

Спасибо!

ответ

2

Ответ зависит от того, как долго вам нужен объект запроса, чтобы он оставался в живых. Если вам не нужно это вне блока try/except, то, вероятно, лучше всего использовать RAII, чтобы удалить его, как только вы покинете этот блок. Например, с помощью наддува :: scoped_ptr, вы можете сделать это:

try { 
    boost::scoped_ptr<QSqlQuery> query(new QSqlQuery(db)); 
    query->prepare(somestmt); 
} 
catch (...) { 
    throwException(); 
} 

Но из вашего примера, это выглядит, как вы хотите сохранить объект запроса, или его копию, вокруг мимо этого блока. Если это нормально, чтобы просто сохранить копию, то вы можете сделать это:

boost::scoped_ptr<QSqlQuery> query(new QSqlQuery(db)); 
try { 
    query->prepare(somestmt); 
} 
catch (...) {   
    QSqlQuery copyOfQuery(*query); 
    throwException(copyOfQuery); 
} 

Или это, если вам не нравится, используя импульс:

QSqlQuery* query = new QSqlQuery(db); 
try { 
    query->prepare(somestmt); 
} 
catch (...) {   
    QSqlQuery copyOfQuery(*query); 
    delete query; 
    throwException(copyOfQuery); 
} 
delete query; 

Если вам необходимо сохранить оригинал сам запрос, тогда вам, вероятно, понадобится сам объект исключения, чтобы удалить его. Т.е., сделать что-то вроде этого:

QSqlQuery* query = new QSqlQuery(db); 
try { 
    query->prepare(somestmt); 
} 
catch (...) {   
    throw MyException(query); 
} 
delete query; 

Где часть договора «MyException» 's является то, что он становится владельцем своего аргумента (то есть, ответственность за удаление).

Другим вариантом является использование общих указателей. Т.е .:

boost::shared_ptr<QSqlQuery> query(new QSqlQuery(db)); 
try { 
    query->prepare(somestmt); 
} 
catch (...) {   
    throwException(query); 
} 

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

+0

woof! ;) Вы действительно набрали все это за 60 секунд? +1 хороший ответ – slashmais

+1

Вы можете использовать 'std :: unique_ptr' и' std :: shared_ptr' вместо 'boost :: scoped_ptr' и' boost :: shared_ptr'. – bames53

+0

Удивительный! Спасибо, Эдвард! – user1065969

0

Вы должны использовать RAII, чтобы обработать это изящно.
Либо используйте умный указатель вместо необработанного указателя, либо используйте класс управления ресурсами для переноса выделенного указателя, чтобы он освобождал выделенный объект при завершении области.

+0

Если в блоке try есть 2 оператора, а первый оператор выдает исключение, будет ли выполняться второй оператор? – user1065969

+0

@ user1065969: Нет, это не так, как только бросок называется управлением, идет к обработчику catch. –

0

Это зависит от вашей программы, если можно повторить подготовить и нужен указатель, чтобы быть действительным, не удаляйте его, в противном случае удалить Memeory и Idealy установить poitner нулевое значение, чтобы отметить его

редактировать: извините непонятый вопрос - измененный ответ

+0

Это не ново, что выбрасывает исключение, оно готово statemnet – user1065969

0

Вы должны изучить RAII pattern. Идея состоит в том, чтобы обернуть QSqlQuery в класс C++, который выполняет очистку в деструкторе. Таким образом, если он выходит из сферы действия (либо throw, return, либо доходит до конца блока, он объявлен в), он разрушается чисто.

+0

Этот запрос должен быть локальной переменной для меня. У меня есть переменная класса, которая является QScopedPointer, к которой я передаю право собственности на этот запрос, как только подготовка будет успешной. – user1065969

+0

Если в блоке try есть 2 оператора, а первый оператор выдает исключение, будет ли выполняться второй оператор? – user1065969

+0

@ пользователь1065969: нет. блок try завершается после того, как будет вызвано исключение, и последующие инструкции не выполняются. –

0

Обычная идиома здесь использовать std::auto_ptr, называя reset на нем , как только вы получили далеко независимо от вашей логики программы зависит от того, взять на себя. Это позволяет избежать необходимости в catch.Так как вам нужно catch в любом случае (чтобы переназначить исключение), вы можете так же легко положить a delete и пропустить std::auto_ptr. (С другой стороны, один ожидает увидеть auto_ptr, и не имея это может привести читателя задавать вопросы.)

0

Вместо не-очистки и hellip;

  QSqlQuery *query = new QSqlQuery(db); 
      try { 
      query->prepare(somestmt); 
      } 
      catch (...) { 
      throwException(*query); 
      } 

просто написать

  QSqlQuery query(db); 
      try { 
       query.prepare(somestmt); 
      } 
      catch (...) { 
       throwException(query); 
      } 

Это его (предполагая, что QSqlQuery имеет надлежащее деструктор).