【问题标题】:Initialize a constant variable and assert if failed (c++)初始化一个常量变量,如果失败则断言(c++)
【发布时间】:2016-07-08 15:28:21
【问题描述】:

我想用 map 中的值初始化 const 变量,并且想断言 map 是否不包含这样的值。

有什么优雅的方法可以实现这一点吗?

我希望 c++ ternary operator ?: 能帮助我解决这个问题,但是这段代码不起作用,因为 ternary operator 想要在两边都有相同的类型。

const auto it = modeMap.find(key);
const Mode myMode = (it != modeMap.end()) ? myMode = it->second : assert(false && "Mode doesn't exist"); 

错误 C2440:“正在初始化”:无法从“void”转换为“const” 模式'

【问题讨论】:

  • 您不能使用三元运算符执行此操作,因为三元运算符要求两个分支返回相同的类型。
  • 使用assert 不适合运行时检查。首先,它会中止程序,看起来就像一个崩溃,这对其他人使用的任何类型的程序都没有好处。其次,它是一个仅用于调试的,如果您创建一个发布版本,断言宏将被空白空间替换。
  • 只要您记得它确实是一个宏,并且在发布版本中它会被替换为空格(这可能会导致语法错误,具体取决于您使用它的位置)。
  • 如果值不在地图中,在禁用断言的生产情况下会发生什么?我认为你应该要么抛出异常,要么终止你的程序。
  • 是的,如果在生产环境中触发,您的程序应该怎么做?现在,它可以做任何事情,可能会产生随机结果。在最好的情况下,它会崩溃。为什么不终止程序并显示错误消息?那将是防御性编程。

标签: c++ c++11


【解决方案1】:

如果您愿意用assert 来引发异常(无论如何这可能是个好主意),您可以通过调用std::map::at 来简化您的代码:

const Mode myMode = modeMap.at(key);

如果key 不在地图中,这将引发std::out_of_range。如果你真的需要assert,那么你可以将逻辑包装在一个函数中:

const Mode& find_or_assert(const std::map<Key, Mode>& modeMap, const Key& key)
{
  auto it = modeMap.find(key);
  assert(it != modeMap.end());
  return it->second;
}

然后

const Mode myMode = find_or_assert(modeMap, key);

【讨论】:

    【解决方案2】:

    如果到达assert 部分,则无法初始化myMode,因为assert 不返回任何内容(void)。您可以使用逗号运算符解决此问题:

    const Mode myMode =
    (it != modeMap.end()) ? myMode = it->second : (assert(false && "Mode doesn't exist"), SOME_VALUE);
    

    在执行assert 时用SOME_VALUE 初始化myMode


    无论如何,您对assert 的使用似乎无效。 Look up如何正确使用。

    【讨论】:

    • static_assert 对测试运行时条件没有多大帮助。
    • @cad 感谢您的链接!
    【解决方案3】:

    最优雅的解决方案是@juanchopanza,但是如果你想assert 并且不抛出异常:

    以我的拙见,最好为这项工作定义一个函数,如下所示:

    const auto it = modeMap.find(key);
    
    Mode& assert_value_exists(std::map<Key_Type, Mode> const& map_, Key_Type const& key) {
      auto it = map_.find(key);
      assert(it != map_.end());
      return it->second;
    }
    

    【讨论】:

    • 如果键不在未定义行为的映射中,则取消引用 map::end()。
    • 我没有看到任何变化。 it-&gt;secondend() 时,你仍然使用它。
    • @Jens if it == map_.end() assert 将被解雇,因此无法返回。
    • 仅当未使用 NDEBUG 编译时。这个问题看起来更像是根本不应该是断言,而是真正的运行时检查,它会以错误消息终止程序。
    【解决方案4】:

    我认为这相当于我的目标。当键存在于映射中时初始化 const 变量,否则产生断言。

    const auto it = modeMap.find(key);
    assert(it != modeMap.end() && "Mode doesn't exist");
    const Mode myMode = it->second;
    

    我同意这里的所有答案,即断言本身并不是一个好的解决方案。并且当断言禁用并且值不在映射中时,在生产情况下是危险的。正如@Jens 提到的,最好抛出异常或终止程序。 (所以其他答案推荐)。

    从防御性编程的角度来看,请不要将此答案视为最佳方式。

    这是对使用 map 中的值初始化 const 变量的问题的答案,如果 map 不包含这样的键,则上升断言。

    已编辑:正如@cad 提到的link

    Assert 宏旨在捕获编程错误,而不是用户或运行时错误,因为它通常在程序退出其调试阶段后被禁用。

    已编辑:还想引用@Joachim Pileborg

    " 使用 assert 不利于运行时检查。首先它会 中止程序,它看起来像一个崩溃,这在 其他人使用的任何程序。其次,它是一个仅用于调试的宏, 如果您创建发布版本,则断言宏将替换为空 空间。只要你记得它真的是一个宏,而且它 将在发布版本中替换为空格(这可能会导致 语法错误取决于您使用它的位置)。 "

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-12-17
      • 2012-05-21
      • 2022-01-10
      • 1970-01-01
      • 1970-01-01
      • 2021-04-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多