C ++ основной вопрос исключения - PullRequest
4 голосов
/ 28 июля 2011

Может кто-нибудь описать, как правильно справиться со следующей ситуацией:

wchar_t* buffer = new wchar_t[...];

if (!something)
{
    throw std::runtime_error("Whatever");
    // Now, at this point I'm leaking memory allocated for the 'buffer'.
}

// Perform actions.
delete[] buffer;

Очевидный способ ее решения означает что-то вроде:

if (!something)
{
    delete[] buffer;
    throw std::runtime_error("Whatever");
}

Теперь - это нормально? (Я подозреваю, что так, но кто знает:)


PS Я понимаю, что есть гораздо лучший способ сделать это - использовать boost::scoped_array или просто std::wstring, что позволяет вызываемым деструкторам освободить выделенную память, просто быть любопытным.

Ответы [ 5 ]

8 голосов
/ 28 июля 2011

Ваше понимание верно.Шаблон

Acquire some resource
Do something
Release resource

в корне неверен, поскольку Do something потенциально может вызвать исключение и утечку ресурса.Более того, вы должны помнить, что нужно освободить ресурс, который является плодородным источником ошибок.

Правильный способ, как вы указали, состоит в том, чтобы всегда использовать объект, деструктор которого освобождает ресурс,Это называется RAII в C ++.

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

Обратите внимание, что некоторые языки (не C ++)укажите ключевое слово finally, которое позволит вам выполнить блок инструкций независимо от того, было ли выброшено исключение.C ++ использует RAII, и вам никогда не следует беспокоиться об освобождении ресурсов, если вы пишете правильные деструкторы.

У меня есть небольшая утилита там для C ++ 0x, которая позволяет выполнять произвольный код в блокевыход, если вы один или два раза взаимодействуете с плохо написанными (или C) библиотеками.

0 голосов
/ 28 июля 2011

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

Как вы говорите, правильный способ - обернуть буфер в класс C ++, деструктор которого будет вызван.Для простого буфера класс с наименьшими издержками, вероятно, является std :: vector, но умный указатель, например boost :: scoped_ptr, также будет работать.

0 голосов
/ 28 июля 2011

Правильный способ - использовать шаблон RAII . Вместо использования необработанного указателя вы должны заключить его в объект, который обрабатывает освобождение памяти в своем деструкторе, например std::wstring или std::unique_ptr.

0 голосов
/ 28 июля 2011

Зависит от того, что что-то есть.Если вычисление something может вызвать исключение, нет, это не будет хорошо.Вы должны заботиться о каждом ресурсе, который вы приобретаете, либо с помощью переменных, выделенных стеком (которые уничтожаются в конце области действия), либо с помощью интеллектуальных указателей различных типов (библиотека std, boost, выбор на ваше усмотрение).

0 голосов
/ 28 июля 2011

Где находится catch? Если он находится в той же области видимости - там можно обработать delete, в противном случае ваш # 2 - правильный вариант. Это при условии, конечно, что вы не хотите делать это правильно, как вы сами упомянули в PS ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...