Как вернуть код ошибки из конструктора?

Я пытаюсь вернуть код ошибки из конструктора, так как конструктор
не возвращает код ошибки, я пытался поставить исключение на
конструктор. Затем в блоке 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;
}

4

Решение

В соответствии с isocpp.org, правильный способ обработки ошибки в конструкторе C ++ состоит в следующем:

Брось исключение.

Невозможно использовать код ошибки, поскольку конструкторы не имеют возвращаемых типов.
Но :

Если у вас нет возможности использовать исключения, «наименее плохой» обходной путь — перевести объект в состояние «зомби», установив внутренний бит состояния, чтобы объект работал как мертвый, даже если он технически еще жив.

Но вы должны действительно использовать исключения, чтобы сигнализировать о сбое в конструкторах, если можете, как сказано:

На практике «зомби» становится довольно уродливым. Конечно, вы должны отдавать предпочтение исключениям над объектами-зомби, но если у вас нет возможности использовать исключения, объекты-зомби могут быть «наименее плохой» альтернативой.

9

Другие решения

Нет способа сделать это. Лучший способ, вероятно, будет иметь статический init() метод, который возвращает экземпляр класса и делает конструктор закрытым. Вы могли бы сделать большую часть строительства из init метод, и просто вернуть код ошибки из этого.

0

Зависит от того, насколько вероятна ваша ошибка и насколько важна правильная инициализация для дальнейшего выполнения программы.

  • Если сбой при инициализации объекта считается исключительным случаем (например, из-за того, что у вас закончилась память), то выдается исключение.
  • Если это ожидаемый сбой, с которым вы хотите разобраться прямо здесь и сейчас, установите объект в состояние сбоя / по умолчанию и разрешите пользователю запрашивать код ошибки (например, когда std::fstream не может открыть файл). Это особенно полезно, если вы хотите повторить инициализацию объекта с другими значениями параметров.

Кстати: если вы решите использовать исключение, я бы, вероятно, не превратил его в код ошибки, если вы абсолютно не обязаны это делать. Исключения там, где они специально разработаны, чтобы вам не приходилось передавать коды ошибок вручную.

0

Добавив слой абстракции поверх вашего конструктора, вы можете достичь своей цели проверки, чтобы убедиться, что конструктор потерпел неудачу, и вернуть код ошибки. Используя шаблон 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;
}
};
0
По вопросам рекламы [email protected]