Я пытаюсь вернуть код ошибки из конструктора, так как конструктор
не возвращает код ошибки, я пытался поставить исключение на
конструктор. Затем в блоке catch я возвращаю соответствующий код ошибки.
Это правильный способ возврата кода ошибки из конструктора?
#include <exception>
#include <iostream>
class A {
public:
A() { throw std::runtime_error("failed to construct"); }
};
int main() {
try {
A a;
} catch (const std::exception& e) {
std::cout << "returining error 1 \n";
return 1;
}
return 0;
}
В соответствии с isocpp.org, правильный способ обработки ошибки в конструкторе C ++ состоит в следующем:
Брось исключение.
Невозможно использовать код ошибки, поскольку конструкторы не имеют возвращаемых типов.
Но :
Если у вас нет возможности использовать исключения, «наименее плохой» обходной путь — перевести объект в состояние «зомби», установив внутренний бит состояния, чтобы объект работал как мертвый, даже если он технически еще жив.
Но вы должны действительно использовать исключения, чтобы сигнализировать о сбое в конструкторах, если можете, как сказано:
На практике «зомби» становится довольно уродливым. Конечно, вы должны отдавать предпочтение исключениям над объектами-зомби, но если у вас нет возможности использовать исключения, объекты-зомби могут быть «наименее плохой» альтернативой.
Нет способа сделать это. Лучший способ, вероятно, будет иметь статический init()
метод, который возвращает экземпляр класса и делает конструктор закрытым. Вы могли бы сделать большую часть строительства из init
метод, и просто вернуть код ошибки из этого.
Зависит от того, насколько вероятна ваша ошибка и насколько важна правильная инициализация для дальнейшего выполнения программы.
std::fstream
не может открыть файл). Это особенно полезно, если вы хотите повторить инициализацию объекта с другими значениями параметров.Кстати: если вы решите использовать исключение, я бы, вероятно, не превратил его в код ошибки, если вы абсолютно не обязаны это делать. Исключения там, где они специально разработаны, чтобы вам не приходилось передавать коды ошибок вручную.
Добавив слой абстракции поверх вашего конструктора, вы можете достичь своей цели проверки, чтобы убедиться, что конструктор потерпел неудачу, и вернуть код ошибки. Используя шаблон Initialize-Shutdown, вы можете быть уверены, что если в вашем конструкторе произойдет ошибка, у вас все равно будет доступ к вашему объекту для очистки всего, что вы выделили. Вот пример:
// This model we can potentially throw an exception from the constructor
class Keyboard {
private:
Device* mDevice;
public:
Keyboard() {
mDevice = ConnectToDevice();
mDevice.Init(); // Say this can throw exception } // If exception thrown, destructor not called and memory is leaked
// The object no longer exists, no way to clean up memory
~Keyboard() { DisconnectFromDevice(mDevice); } // DisconnectFromDevice() cleans up some dynamically allocated memory
};
// This model we use a Initialize-Shutdown pattern
class Keyboard {
private:
Device* mDevice;
bool IsInitialized = false;
public:
Keyboard() {}
~Keyboard() { DisconnectFromDevice(mDevice); } // DisconnectFromDevice() cleans up some dynamically allocated memory
void Initialize() {
mDevice = ConnectToDevice();
if (this.mDevice == nullptr)
status = -1;
mDevice.Init(); // Caller still needs to catch exception if it throws
// If exception is thrown here, the caller is responsible for cleaning up
// However, the object is still alive so caller can manually call or other cleaning method
IsInitialized = true;
return;
}
void Shutdown() {
if (IsInitialized)
DisconnectFromDevice(mDevice);
return;
}
};