Страницы

Поиск по вопросам

среда, 4 марта 2020 г.

С++ аварийный выход из конструктора

#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) { // Обработка исключения из конструктора, ресурсы будут освобождены } }

Комментариев нет:

Отправить комментарий