Есть отличные ответы, поэтому я просто добавляю кое-что забытое.
0. RAII касается областей применения
RAII касается обоих:
- получение ресурса (независимо от того, какой ресурс) в конструкторе и отмена его получения в деструкторе.
- выполнение конструктора при объявлении переменной и автоматическое выполнение деструктора, когда переменная выходит за пределы области видимости.
Другие уже ответили об этом, поэтому я не буду вдаваться в подробности.
1. При кодировании на Java или C # вы уже используете RAII ...
MONSIEUR JOURDAIN: Что? Когда я говорю: «Николь, принеси мне тапочки и дай мне ночной колпак» - это проза?
МАСТЕР ФИЛОСОФИИ: Да, сэр.
MONSIEUR JOURDAIN: Более сорока лет я говорю прозой, ничего не зная о ней, и я очень благодарен вам за то, что вы меня этому научили.
- Мольер: Джентльмен среднего класса, Акт 2, Сцена 4
Как и мсье Журден с прозой, C # и даже Java люди уже используют RAII, но скрытыми способами. Например, следующий код Java (который на C # написан таким же образом, заменяясь synchronized
на lock
):
void foo()
{
// etc.
synchronized(someObject)
{
// if something throws here, the lock on someObject will
// be unlocked
}
// etc.
}
... уже использует RAII: получение мьютекса выполняется с помощью ключевого слова ( synchronized
или lock
), а отмена получения будет выполнена при выходе из области видимости.
Это настолько естественное обозначение, что почти не требует объяснений даже для людей, которые никогда не слышали о RAII.
Преимущество C ++ над Java и C # в том, что с помощью RAII можно сделать все, что угодно. Например, нет прямого встроенного эквивалента synchronized
или lock
в C ++, но мы все еще можем их иметь.
В C ++ это было бы написано:
void foo()
{
// etc.
{
Lock lock(someObject) ; // lock is an object of type Lock whose
// constructor acquires a mutex on
// someObject and whose destructor will
// un-acquire it
// if something throws here, the lock on someObject will
// be unlocked
}
// etc.
}
который можно легко написать на языке Java / C # (с использованием макросов C ++):
void foo()
{
// etc.
LOCK(someObject)
{
// if something throws here, the lock on someObject will
// be unlocked
}
// etc.
}
2. RAII имеет альтернативное использование
БЕЛЫЙ КРОЛИК: [поет] Я опаздываю / Я опаздываю / На очень важное свидание. / Нет времени говорить «Привет». / Прощай. / Я опаздываю, я опаздываю, я опаздываю.
- Алиса в стране чудес (версия Диснея, 1951)
Вы знаете, когда будет вызван конструктор (при объявлении объекта), и вы знаете, когда будет вызван его соответствующий деструктор (на выходе из области видимости), поэтому вы можете написать почти волшебный код, используя только строку. Добро пожаловать в страну чудес C ++ (по крайней мере, с точки зрения разработчика C ++).
Например, вы можете написать объект счетчика (я позволил это в качестве упражнения) и использовать его, просто объявив его переменную, как был использован объект блокировки выше:
void foo()
{
double timeElapsed = 0 ;
{
Counter counter(timeElapsed) ;
// do something lengthy
}
// now, the timeElapsed variable contain the time elapsed
// from the Counter's declaration till the scope exit
}
что, конечно же, может быть написано, опять же, способом Java / C # с использованием макроса:
void foo()
{
double timeElapsed = 0 ;
COUNTER(timeElapsed)
{
// do something lengthy
}
// now, the timeElapsed variable contain the time elapsed
// from the Counter's declaration till the scope exit
}
3. Почему не хватает C ++ finally
?
[SHOUTING] Это последний обратный отсчет!
- Европа: последний отсчет времени (извините, у меня не было цитат, здесь ... :-)
Предложение finally
используется в C # / Java для обработки удаления ресурсов в случае выхода из области действия (либо посредством return
исключения, либо сгенерированного исключения).
Проницательные читатели спецификации заметят, что в C ++ нет пункта finally. И это не ошибка, потому что C ++ в этом не нуждается, поскольку RAII уже обрабатывает удаление ресурсов. (И поверьте мне, написать деструктор C ++ намного проще, чем написать правильное предложение finally в Java или даже правильный метод Dispose в C #).
Тем не менее, иногда finally
оговорка была бы крутой. Можем ли мы сделать это на C ++? Да мы можем! И снова с альтернативным использованием RAII.
Вывод: RAII - это больше, чем философия в C ++: это C ++
RAII? ЭТО С ++ !!!
- Возмущенный комментарий разработчика C ++, беззастенчиво скопированный малоизвестным королем Спарты и его 300 друзьями
Когда вы достигнете определенного уровня опыта в C ++, вы начнете мыслить в терминах RAII , в терминах автоматического выполнения конструкторов и деструкторов .
Вы начинаете думать в терминах областей , а также {
и }
персонажи становятся одними из самых важных в вашем коде.
И почти все подходит с точки зрения RAII: безопасность исключений, мьютексы, соединения с базой данных, запросы к базе данных, соединение с сервером, часы, дескрипторы ОС и т. Д., И, наконец, что не менее важно, память.
Часть базы данных не является незначительной, так как, если вы согласитесь заплатить цену, вы даже можете писать в стиле « транзакционного программирования », выполняя строки и строки кода, пока в конце концов не решите, хотите ли вы зафиксировать все изменения или, если это невозможно, возврат всех изменений (при условии, что каждая строка удовлетворяет хотя бы Строгой гарантии исключения). (см. вторую часть статьи Herb's Sutter о транзакционном программировании).
И как в пазле, все подходит.
RAII - это неотъемлемая часть C ++, без него C ++ не мог бы быть C ++.
Это объясняет, почему опытные разработчики C ++ так влюблены в RAII и почему RAII - это первое, что они ищут, пробуя другой язык.
И это объясняет, почему сборщик мусора, хотя сам по себе является великолепной технологией, не так впечатляет с точки зрения разработчика C ++:
- RAII уже обрабатывает большинство случаев, обрабатываемых GC
- Сборщик мусора лучше, чем RAII, справляется с циклическими ссылками на чистые управляемые объекты (смягчается за счет разумного использования слабых указателей)
- Тем не менее, сборщик мусора ограничен памятью, тогда как RAII может обрабатывать любые виды ресурсов.
- Как описано выше, RAII может делать гораздо больше ...