Изпълних примерна програма и наистина се извикват деструктори за обекти, разпределени в стека, но това гарантирано ли е от стандарта?
Деструкторите извикват ли се след хвърляне в C++?
Отговори (3)
Да, гарантирано е (при условие, че изключението е уловено), до реда, в който се извикват деструкторите:
C++11 15.2 Конструктори и деструктори [except.ctor]
1 Тъй като управлението преминава от израз за хвърляне към манипулатор, деструкторите се извикват за всички автоматични обекти, конструирани след въвеждането на блока try. Автоматичните обекти се унищожават по реда, обратен на завършване на изграждането им.
Освен това, ако изключението бъде хвърлено по време на изграждането на обект, подобектите на частично изградения обект се гарантира, че ще бъдат правилно унищожени:
2 Обект с каквато и да е продължителност на съхранение, чиято инициализация или унищожаване е прекратено от изключение, ще има деструктори, изпълнени за всички негови напълно конструирани подобекти (с изключение на вариантните членове на клас, подобен на обединение), тоест за подобекти, за които основният конструктор (12.6.2) е завършил изпълнението и деструкторът все още не е започнал изпълнението. По същия начин, ако неделегиращият конструктор за обект е завършил изпълнението и делегиращ конструктор за този обект излезе с изключение, ще бъде извикан деструкторът на обекта. Ако обектът е бил разпределен в нов израз, съвпадащата функция за освобождаване (3.7.4.2, 5.3.4, 12.5), ако има такава, се извиква, за да освободи паметта, заета от обекта.
Целият този процес е известен като „размотаване на стека“:
3 Процесът на извикване на деструктори за автоматични обекти, конструирани по пътя от блок try до израз за хвърляне, се нарича „размотаване на стека“. Ако деструктор, извикан по време на размотаване на стека, излезе с изключение, се извиква std::terminate (15.5.1).
Развиването на стека формира основата на широко използваната техника, наречена Придобиването на ресурс е инициализация (RAII).
Обърнете внимание, че размотаването на стека не се извършва непременно, ако изключението не е уловено. В този случай зависи от реализацията дали ще се извърши размотаването на стека. Но независимо дали отвиването на стека е извършено или не, в този случай ви е гарантирано последно извикване на std::terminate
.
C++11 15.5.1 Функцията std::terminate() [except.terminate]
2 В ситуация, в която не е намерен съвпадащ манипулатор, се дефинира от изпълнението дали стекът се развива или не, преди да се извика
std::terminate()
.
Да, гарантирано е, че деструкторите ще бъдат извикани при размотаване на стека, включително размотаване поради хвърляне на изключение. Има само няколко трика с изключения, които трябва да запомните:
- Деструкторът на класа не се извиква, ако в неговия конструктор е хвърлено изключение.
- Изключението автоматично се хвърля отново, ако бъде уловено в блока за улавяне на списъка за инициализация на конструкцията.
terminate()
вашия процес. Ще ми е интересно да видя контрапримери...
- person DevSolar; 29.11.2011
release
метод.
- person Cheers and hth. - Alf; 29.11.2011
try
, изпълнено в деструктор). Visual C++ никога не е прилагал функцията на стандарта за проверка и тази функция така или иначе не е адекватна. така че, това е малко проблематично, но не е тотално, тъй като кодът за използване може да бъде проектиран около него.
- person Cheers and hth. - Alf; 29.11.2011
Ако хвърлянето е уловено, тогава нормално cpp операциите продължават. Това включва деструктори и изскачане на стека. Ако обаче изключението не бъде уловено, изскачането на стека не е гарантирано.
Също така голо хвърляне или празно хвърляне не може да бъде уловено от моя мобилен компилатор.
пример:
#include <Jav/report.h>
int main()
{
try { throw; }
catch(...) { rep("I bet this is not caught"); }
}