【问题标题】:Throwing exception in initialisation list?在初始化列表中抛出异常?
【发布时间】:2020-10-17 14:49:04
【问题描述】:

我有以下代码:

在 Game.h 中:

mtm::Dimensions dimensions;
std::vector<std::shared_ptr<Character>> board;

在 Game.cpp 中:

Game::Game(int height, int width) : dimensions(height, width), board(height * width, nullptr) 
{
    if (height <= 0 || width <= 0) {
        throw mtm::IllegalArgument();
    }
}

但是您可能注意到我抛出错误太晚了,如果height * width 小于 0,那么将抛出 bad_alloc 而不是 IllegalArgument,我该如何解决这个问题?

有没有办法在初始化列表中抛出异常?

【问题讨论】:

  • 如果可以的话,将检查移到mtm::Dimensions 的构造函数中。解决您的问题,并且似乎是验证尺寸的更合乎逻辑的地方。
  • 我做不到 @user4581301
  • Rats.How 添加一个辅助函数来执行检查并返回 heightwidth 的乘积。 board(height * width, nullptr) 变为 board(helper(height, width), nullptr)
  • @user4581301 并且该辅助函数返回 IllegalArgument?听起来不错,但有没有办法在没有辅助功能的情况下做到这一点? (听说可以)
  • 附言。你可以使用宏gcc.godbolt.org/z/HZqAFL

标签: c++ class methods


【解决方案1】:

你可以先捕捉board的构造中抛出的bad_alloc,然后再抛出你自己的自定义异常:

Game::Game(int height, int width) try : dimensions(height, width), board(height * width, nullptr) 
{
    if (height <= 0 || width <= 0) {
        throw mtm::IllegalArgument();
    }
}
catch(...)  // or specifically bad_alloc
{
   throw mtm::IllegalArgument();  // or some other custom exception
}

这是基于您在 cmets 中的建议的另一个(更好的)答案:

Game::Game(int height, int width) : 
  dimensions(height, width), 
  board((height * width > 0 ? height * width : throw mtm::IllegalArgument()), 
        nullptr) 
{
  // ...
}

这是demo

【讨论】:

  • 我想在没有足够内存的时候离开 bad_alloc 并且不要用 IllegalArgument() 替换每个 bad_alloc
  • 哦,我明白了。不确定是否有没有辅助函数的方法。
  • 有人建议(并删除)Game::Game(int height, int width):board((height
  • 这绝对是可能的。你试过了吗?如果可行,您可以发布答案。
  • 看到了吗?总有一些东西,即使这个并不是那么令人兴奋。现在让我们用五十页的宏和模板来试试吧!
【解决方案2】:

插入一个辅助函数来验证heightwidth

size_t helper(int height, int width)
{
    如果(高度 
    

【讨论】:

    【解决方案3】:

    如果您无法在mtm::Dimensions 中进行检查,它确实应该在那里,您可以使用辅助函数:

    int throw_if_not_positive(int x) {
        if (x <= 0) throw mtm::IllegalArgument();
        return x;
    }
    
    Game::Game(int height, int width) : 
        dimensions(throw_if_not_positive(height),
                   throw_if_not_positive(width)), 
        board(height * width, nullptr) 
    {
    }
    

    或者使用unsigned,或者使用

    struct positive_int {
         int value;
         positive_int(int x) : value(x) {
            if (x <= 0)  throw mtm::IllegalArgument();
         }
         operator int(){ return value; }
    };
    
    Game::Game(positive_int height, positive_int width) : 
        dimensions(height,width), 
        board(height * width, nullptr) 
    {
    }
    

    【讨论】:

    • 谢谢,我很好奇你的解决方案比 user4581301 解决方案有优势吗?
    • 我喜欢这个的地方在于它在dimension 之前捕获了错误,因此它会提前失败,而不会浪费构建维度的努力。
    • @BigSur 我更喜欢有空的构造函数,我更喜欢在类型而不是函数中进行此类检查。如果我可以选择,我会在构建dimensions 时进行检查,但由于您排除了这一点,我会选择最后一个。对于您的最后一条评论,我不明白您的意思,在第一个示例中,构造函数的主体为空
    • @BigSur 抱歉,user4581301 已经进行了编辑。这里已经很晚了;)
    • 这似乎是合乎逻辑的事情。这是一个如此明显的大脑衰退。在 BigSur 指出之前,我的大脑甚至没有注意到代码仍然存在。
    猜你喜欢
    • 2013-07-07
    • 1970-01-01
    • 2011-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-05
    相关资源
    最近更新 更多