Программирование на C ++ - PullRequest
0 голосов
/ 28 марта 2012

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

Например, скажите

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

Здесь, где и как мне удалить запрос, если выброшено исключение?

Спасибо!

Ответы [ 6 ]

2 голосов
/ 28 марта 2012

Ответ зависит от того, как долго вам нужен объект запроса, чтобы остаться в живых.Если вам не нужно это вне блока try / Кроме того, вероятно, лучше использовать RAII, чтобы удалить его, как только вы выходите из этого блока.Например, используя boost :: 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);
}

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

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» заключается в том, что он вступает во владение своим аргументом (т.е. несет ответственность за его удаление).

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

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

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

0 голосов
/ 28 марта 2012

Вместо "без очистки"

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

просто напишите

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

Вот и все (при условии, что QSqlQuery имеет правильный деструктор).

0 голосов
/ 28 марта 2012

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

0 голосов
/ 28 марта 2012

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

0 голосов
/ 28 марта 2012

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

edit: извините, неправильно понял вопрос - изменил ответ

0 голосов
/ 28 марта 2012

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

...