Sé que se recomienda no lanzar una excepción en el constructor, pero necesito usar el cambio de caso en el constructor, me pregunto cómo debo manejar el caso predeterminado, al que en realidad no se debe acceder.
enum LengthUnit { MILLIMETERS = 0, MICROMETERS, NANOMETERS, }; class Length { public: constexpr Length(double value, LengthUnit unit) noexcept { switch(unit) { case MILLIMETERS: mNanometers = value * 1e6; break; case MICROMETERS: mNanometers = value * 1e3; break; case NANOMETERS: mNanometers = value; break; default: { // accessed when called Length(1, LengthUnit(10)), not permitted // throw std::exception(); } } private: int mNanometers; };Su conocimiento es incorrecto. A menudo se recomienda lanzar una excepción del constructor cuando falla la construcción. La captura de excepciones suele ser lo más conveniente, pero no siempre. La conveniencia a menudo no es la razón por la que usamos C++.
Entonces, si no desea arrojar desde los constructores, debe tener algún tipo de estado "malo", "inexistente" o "mal construido" de objetos mal construidos (y, por lo tanto, almacenamiento para esos estados en objetos) y también manejar esos estados explícitamente con estilo if (length.isBad()) not capturando excepciones. Eso a menudo no se recomienda.
Si arroja una excepción en el constructor, el destructor no se ejecutará automáticamente. Este es un problema si tiene una adquisición manual de recursos en el constructor que debe liberarse manualmente en el destructor. Pero no es un problema lanzar una excepción en el constructor si tiene objetos automáticos en la clase, responsables de adquirir/liberar recursos. Se invocarán los destructores de miembros automáticos. Si necesita la adquisición manual de recursos, cree una clase separada que administre automáticamente el recurso y utilícelo en su clase.
Una buena idea, esto ya se sugiere en los comentarios, use la clase enum, que protegerá su código en el momento de la compilación:
enum class LengthUnit : int { MILLIMETERS = 0, MICROMETERS, NANOMETERS, }; La otra opción, si aún necesita no lanzar desde el constructor, todavía hay una forma de indicar el estado no válido del objeto. Usando una variable miembro. Pero su clase tal como está no tiene problemas para lanzar una excepción desde el constructor. También usar la variable de estado es redundante si usa enum class :
class Length { public: Length(double value, LengthUnit unit) noexcept { switch(unit) { case LengthUnit::MILLIMETERS: mNanometers = value * 1e6; break; case LengthUnit::MICROMETERS: mNanometers = value * 1e3; break; case LengthUnit::NANOMETERS: mNanometers = value; break; default: valid = false; } } bool isValid(){return valid;} bool isInvalid(){return !valid;} private: bool valid = true; int mNanometers = 0; };