#cpp #исключения #конструктор
Можно ли во время создания объекта, при сбое в конструкторе завершить его без создания объекта и оповестить об этом программу? serialPort::serialPort(LPSTR serialName) { HANDLE serialDesc; // COM openning serialDesc = CreateFile(serialName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); if (serialDesc == INVALID_HANDLE_VALUE) { // сделать что-то, что бы объект не создавался и оповестить программу } } Мне в голову приходят только передача указателя на внешнюю структуру с последующей проверкой, или содержать дополнительную переменную в классе, которую так же придется проверять извне. Еще прочитал про try-throw-catch, но не могу найти явную информацию как он работает в конструкторе.
Ответы
Ответ 1
Вообще-то генерация исключения в конструкторе и означает, что объект не создан... Само собой, все действия по очистке уже сделанного в конструкторе вы должны выполнить самостоятельно.Ответ 2
я обязан их закрыть в ручную, иначе они будут считаться открытыми, а их дескрипторы утеряны? закрывать обязательно нужно, так как во первых будет потеря ресурсов - файловых дескрипторов + памяти. Если ваша программа работает 24х7х365, то если эти объекты создаются постоянно, то ваша программа может аварийно завершиться. Вопрос как? Если вы сгенерируете исключение в конструкторе, а файл - член этого класса? Стандартный подход 1) в конструкторе не делать инициализую переменных (например просто их нулить) а делать это в отдельном методе, например init, которое может сгенерировать исключение, которое может быть обработано сверху.В этом подходе, у вас будет вызван деструктор, который будет освобождать ресурсы 2) Использовать наследование 3) Использовать умные указатели для членов класса, тут все понятно Пример 1 решения class Foo { FILE* f; public: Foo() { f = 0; } virtual ~Foo() { if ( 0 != f) fclose(f); } bool init() { f = fopen("file.txt", "+rw"); if ( !f ) { throw 1; } fseek(f, 0, SEEK_END); size_t fileSize = ftell(f); if (fileSize < 100) return false; return true; } }; int main() { { Foo f; try { f.init(); } catch (int& e) { // Обработка исключения, о ресурсах не беспокоимся, деструктор // класса Foo все сделает } } } Второй способ основан на том, чтобы поместить f в базовый класс и и там освобождать ресурсы ( при исключении в конструкторе порожденного класса, вызовется и деструктор базового) Пример 2 Решения Перенесем метод инит в конструктор порожденного класса class Foo { FILE* f; public: Foo() { f = 0; } virtual ~Foo() { if ( 0 != f) fclose(f); } }; class Delivery: public Foo { bool fileIsBig; public: Delivery(const char* fileName) { fileIsBig = true; f = fopen(fileName, "+rw"); if ( !f ) { throw 1; } fseek(f, 0, SEEK_END); size_t fileSize = ftell(f); if (fileSize < 100) fileIsBig = false; } virtual ~Delivery() { } }; int main() { try { Delivery d("myfile"); } catch (int& e) { // Обработка исключения из конструктора, ресурсы будут освобождены } }
Комментариев нет:
Отправить комментарий