【问题标题】:handle default case in c++ constructor在 C++ 构造函数中处理默认情况
【发布时间】:2021-10-29 22:32:57
【问题描述】:

我知道建议不要在构造函数中抛出异常,但我需要在构造函数中使用switch case,我想知道我应该如何处理default case,实际上不应该访问。

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;
};
  1. constexpr 用于加速编译时计算值
  2. noexcept 被标记为构造函数不应抛出异常

【问题讨论】:

  • 谁告诉你“构造函数不建议抛出异常”?这是表示对象构造问题的唯一方法。
  • 如果您想保证不会使用无效参数调用 ctor,您将派生三个类并使 Length::Length() 受保护。如果您想防止“错字”,请使用enum class LengthUnit: int {...}
  • @Yksisarvinen:对不起,我发现异常不应该在析构函数而不是构造函数中抛出,非常感谢!!!
  • 如果对象的构造由于某种原因失败(例如,如果它不能确保对象的状态有效,则强烈建议在构造函数中抛出异常分配一个资源[内存、互斥体等],该资源对于对象运行至关重要,但资源分配失败等)。
  • 虽然 (C++17),godbolt.org/z/4cahY9Grf,但有一种方法可以在没有开关的情况下创建构造函数。此外,我建议您将表示物理单位的值存储为 SI 标准(因此长度为米)。然后提供功能以提供纳米(如果您愿意)。或者用你使用的单位来真正命名你的班级

标签: c++ exception constructor switch-statement


【解决方案1】:

你的知识不正确。通常建议在构造失败时从构造函数中抛出异常。捕获异常通常是最方便的,但并非总是如此。方便往往不是我们使用 C++ 的原因。

因此,如果不想从构造函数中抛出,那么您应该有某种“坏”、“不存在”或“错误构造”状态的错误构造对象(以及将这些状态存储在对象)并且还以if (length.isBad()) 风格显式处理这些状态,而不是通过捕获异常。通常不建议这样做。

【讨论】:

    【解决方案2】:

    如果你在构造函数中抛出异常,那么析构函数将不会自动执行。如果您在构造函数中手动获取资源而必须在析构函数中手动释放,这将是一个问题。但是如果你在类中有自动对象,负责获取/释放资源,那么在构造函数中抛出异常是没有问题的。将调用自动成员的析构函数。如果您需要手动获取资源,请创建一个自动管理资源的单独类,并在您的类中使用它。
    一个好主意,在 cmets 中已经建议,使用 enum 类,它将在编译时保护您的代码:

    enum class LengthUnit : int 
    {
        MILLIMETERS = 0,
        MICROMETERS,
        NANOMETERS,
    };
    

    另一个选项,如果你仍然需要不从构造函数中抛出,还有一种方法可以指示对象的无效状态。使用成员变量。但是你的类没有从构造函数抛出异常的问题。如果您使用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;
    };
    

    【讨论】:

      猜你喜欢
      • 2018-11-25
      • 1970-01-01
      • 2014-05-15
      • 1970-01-01
      • 2012-06-30
      • 2016-06-17
      • 2020-11-22
      • 2020-05-14
      相关资源
      最近更新 更多