带有断言的C ++ static_cast

时间:2014-05-23 13:17:08

标签: c++

不幸的是,我必须在调用第三方库时执行缩小演员。我不想在我的发布版本中施加开销,因此将使用static_cast。然而,它是一个数组索引,如果它最终消极,可能会导致一些娱乐。有没有办法在调试模式下创建一个安全的强制转换,它会检查值以确保在转换过程中没有丢失?我能想到的唯一方法就是使用宏,而我宁愿不这样做。

例如,在使用MSVC的发布和调试模式下:

int main() {
  long long ll = std::numeric_limits<long>::max();
  ++ll;
  std::cout << ll << "\n";
  long l = static_cast<long>(ll);
  std::cout << l << "\n";
}

导致输出:

2147483648
-2147483648

使用宏:

template<class to, class from>
to checked_static_cast(const from& from_value) {
  to to_value = static_cast<to>(from_value);
  if (static_cast<from>(to_value) != from_value)
    throw std::runtime_error("Naughty cast");
  return to_value;
}

#ifdef _DEBUG
#define debug_checked_static_cast(to, val) checked_static_cast<to>(val)
#else
#define debug_checked_static_cast(to, val) static_cast<to>(val)
#endif

int main() {
  try {
    long long ll = std::numeric_limits<long>::max();
    ++ll;
    std::cout << ll << "\n";
    long l = debug_checked_static_cast(long, ll);
    std::cout << l << "\n";
  } catch (const std::exception& e) {
    std::cerr << "ERROR: " << e.what() << "\n";
  }
}

在发布模式下产生相同的输出,但调试中的以下内容:

2147483648
ERROR: Naughty cast

有更好的选择吗?

注意:我忽略了我们可能从一个足以引起这个问题的阵列中获得的娱乐,也许这只是过度偏执,但我想这个概念可能有我的特定要求以外的应用程序。

2 个答案:

答案 0 :(得分:7)

不需要宏,只需在函数体内使用预处理器条件:

template<class to, class from>
inline to debug_checked_static_cast(const from& from_value) {
  to to_value{static_cast<to>(from_value)};
#if _DEBUG
  from round_trip{to_value};
  if (round_trip != from_value)
    throw std::runtime_error("Naughty cast");
#endif
  return to_value;
}

template<class to, class from>
inline to debug_checked_coercion(const from& from_value) {
  to to_value{from_value};
#if _DEBUG
  from round_trip{to_value};
  if (round_trip != from_value)
    throw std::runtime_error("Naughty cast");
#endif
  return to_value;
}

然后使用

long l = debug_checked_coercion<long>(ll);

请注意,我已尽量减少static_cast的使用,因为缩小数字转换并不需要。

答案 1 :(得分:0)

我倾向于同意dlf,如果它足够重要,可以在Debug中抛出异常,那么你应该也可以在Release中这样做。

如果我选择了有时会崩溃的高效代码,而且效率稍低的代码并不知道我会选择什么。

保罗。