- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我已经使用std::chrono
多年了,并且看了很多Howard Hinnant的
讨论了库的设计和使用。我喜欢,而且我总体上认为
明白它。但是,最近,我突然意识到我不知道该怎么做
切实安全地使用它,以避免不确定的行为。
在我处理一些案例时,请多包涵我为我准备的舞台
问题。
让我们从我认为是“最简单”的std::chrono::duration
类型开始,nanoseconds
。其最小rep
大小为64位,这意味着实际上
将是std::int64_t
,因此可能没有“剩余”可选
标准不需要的代表性位。
此功能显然并不总是安全的:
nanoseconds f1(nanoseconds value)
{ return ++value; }
value
是
nanoseconds::max()
,则此溢出,我们可以确认
-fsanitize=undefined
):
runtime error: signed integer overflow: 9223372036854775807 + 1 cannot be
represented in type 'std::__1::chrono::duration<long long,
std::__1::ratio<1, 1000000000> >::rep' (aka 'long long')
std::int64_t f2(std::int64_t value)
{ return ++value; }
value
尚未达到最大值时,我们首先检查一下,
nanoseconds f3(nanoseconds value)
{
if(value == value.max())
{
throw std::overflow_error{"f3"};
}
return ++value;
}
nanoseconds
值,我们想添加另一个
nanoseconds
值为,天真的方法是:
struct Foo
{
// Pretend this can be set in other meaningful ways so we
// don't know what it is.
nanoseconds m_nanos = nanoseconds::max();
nanoseconds f4(nanoseconds value)
{ return m_nanos + value; }
};
runtime error: signed integer overflow: 9223372036854775807 +
9223372036854775807 cannot be represented in type 'long long'
Foo{}.f4(nanoseconds::max()) = -2 ns
struct Foo
{
explicit Foo(nanoseconds nanos = nanoseconds::max())
: m_nanos{nanos}
{}
// Again, pretend this can be set in other ways, so we don't
// know what it is.
nanoseconds m_nanos;
nanoseconds f5(nanoseconds value)
{
if(m_nanos > m_nanos.zero() && value > m_nanos.max() - m_nanos)
{
throw std::overflow_error{"f5+"};
}
else if(m_nanos < m_nanos.zero() && value < m_nanos.min() - m_nanos)
{
throw std::overflow_error{"f5-"};
}
return m_nanos + value;
}
};
Foo{}.f5(0ns) = 9223372036854775807 ns
Foo{}.f5(nanoseconds::min()) = -1 ns
Foo{}.f5(1ns) threw std::overflow_error: f5+
Foo{}.f5(nanoseconds::max()) threw std::overflow_error: f5+
Foo{nanoseconds::min()}.f5(0ns) = -9223372036854775808 ns
Foo{nanoseconds::min()}.f5(nanoseconds::max()) = -1 ns
Foo{nanoseconds::min()}.f5(-1ns) threw std::overflow_error: f5-
Foo{nanoseconds::min()}.f5(nanoseconds::min()) threw std::overflow_error: f5-
nanoseconds f6(hours value)
{ return m_nanos + value; }
f4()
一样的问题。我们可以解决与
f5()
吗?让我们使用与
f5()
相同的主体,但只需更改参数
nanoseconds f7(hours value)
{
if(m_nanos > m_nanos.zero() && value > m_nanos.max() - m_nanos)
{
throw std::overflow_error{"f7+"};
}
else if(m_nanos < m_nanos.zero() && value < m_nanos.min() - m_nanos)
{
throw std::overflow_error{"f7-"};
}
return m_nanos + value;
}
nanoseconds::max()
和
m_nanos
添加
value
。所以当我们
Foo{}.f7(0h) = 9223372036854775807 ns
/usr/lib/llvm-7/bin/../include/c++/v1/chrono:880:59: runtime error: signed
integer overflow: -9223372036854775808 * 3600000000000 cannot be represented
in type 'long long'
Foo{}.f7(hours::min()) = 9223372036854775807 ns
Foo{}.f7(1h) threw std::overflow_error: f7+
Foo{}.f7(hours::max()) DIDN'T THROW!!!!!!!!!!!!!!
Foo{nanoseconds::min()}.f7(0h) = -9223372036854775808 ns
terminating with uncaught exception of type std::overflow_error: f7-
Aborted
Foo{}.f7(hours::min())
。但是那种情况
hours
和
nanoseconds
的行为也涉及
std::common_type
的使用,
std::chrono
定义了
duration
类型
period
值的最大公约数的术语。就我们而言
nanoseconds
,所以首先将
hours
转换为
nanoseconds
。一种
libc++
的摘录显示了部分内容:
template <class _LhsDuration, class _RhsDuration>
struct __duration_lt
{
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
bool operator()(const _LhsDuration& __lhs, const _RhsDuration& __rhs) const
{
typedef typename common_type<_LhsDuration, _RhsDuration>::type _Ct;
return _Ct(__lhs).count() < _Ct(__rhs).count();
}
};
hours
value
是否足够小以适合
nanoseconds
(关于此特定的标准库实现,及其
rep
类型选择),以下基本上是等效的:
if(m_nanos > m_nanos.zero() && value > m_nanos.max() - m_nanos)
if(m_nanos > m_nanos.zero() && nanoseconds{value} > m_nanos.max() - m_nanos)
hours
使用32位
rep
,将存在相同的问题:
runtime error: signed integer overflow: 2147483647 * 3600000000000 cannot be
represented in type 'long long'
value
足够小,包括限制
rep
大小,我们最终可以使它变得合适。 。 。因为很明显一些
hours
值
nanoseconds
,否则转换将毫无意义。
hours
转换为
nanoseconds
,而不会溢出
nanoseconds::rep
类型。再次,像我们一样
nanoseconds f8(hours value)
{
assert(value >= value.zero());
if(value.count()
> std::numeric_limits<nanoseconds::rep>::max() / 3600000000000)
{
throw std::overflow_error{"f8+"};
}
return value;
}
nanoseconds::rep
的选择:
f8(0h) = 0 ns
f8(1h) = 3600000000000 ns
f8(2562047h) = 9223369200000000000 ns
f8(2562048h) threw std::overflow_error: f8+
f8(hours::max()) threw std::overflow_error: f8+
hours
和
nanoseconds
之间转换,这会破坏重点。
period
类型之间的关系(其中只有一个乘法是
duration
类型,仅支持无损转换:
template <typename target_duration, typename source_duration>
target_duration lossless(source_duration duration)
{
// ... ?
}
duration
中的所有逻辑
lossless()
,它可以执行
operator+()
,所以我们失去了巨大的表现力
duration
值的一部分。
duration_cast
加入混合有损转换,这似乎毫无希望。
template <typename duration1, typename duration2>
bool isSafe(duration1 limit, duration2 reading)
{
assert(limit >= limit.zero());
return reading < limit / 2;
}
grace
有所了解:
template <typename duration1, typename duration2>
bool isSafe2(duration1 limit, duration2 reading, milliseconds grace)
{
assert(limit >= limit.zero());
assert(grace >= grace.zero());
const auto test = limit / 2;
return grace < test && reading < (test - grace);
}
duration1
和
duration2
确实可以是任何
duration
类型(包括
std::chrono::duration<std::int16_t, std::ratio<3, 7>>
这样的东西,我看不到
duration
类型,有很多可怕的结果。
std::chrono
,这些类型的解决方案似乎“更糟”
std::chrono
第一名。
duration
创建自己的
rep
类型,我想我
std::chrono
可以保持我在每种情况下选择的精确分辨率。如果我
double
可以在各处计算秒数,而不是混合使用单位。但是如果那是一个
std::chrono
(甚至
struct timespec
)。
std::chrono
进行操作
duration
类型,更不用说所有可能的
duration
的丰富世界
最佳答案
效果最好的答案是了解您的域,并且不要在所使用精度的最大范围附近进行编程。如果您使用nanoseconds
,则范围为+/- 292年。不要走那么远。如果您需要的范围不仅仅是+/- 100年,请使用比纳秒更大的分辨率。
如果您可以遵循这些规则,那么您就不必担心溢出。
有时候你做不到。例如,如果您的代码必须处理不受信任的输入或常规输入(例如,通用库),那么您确实需要检查溢出。
一种技术是选择rep
只是为了进行比较,它可以处理比任何人都需要的范围更大的范围。在这种情况下,int128_t
和double
是我可以使用的两个工具。例如,这是一个checked_convert
,它在实际执行double
之前使用duration_cast
检查溢出:
template <class Duration, class Rep, class Period>
Duration
checked_convert(std::chrono::duration<Rep, Period> d)
{
using namespace std::chrono;
using S = duration<double, typename Duration::period>;
constexpr S m = Duration::min();
constexpr S M = Duration::max();
S s = d;
if (s < m || s > M)
throw std::overflow_error("checked_convert");
return duration_cast<Duration>(d);
}
std::thread::sleep_for
,则值得这样做。
lcm_type
(不是一个好名字)。这与
common_type_t<Duration1, Duration2>
相反。它没有找到两个输入的
duration
都可以无损地转换成的
duration
(无除法),而是找到了两个输入的
duration
都可以无转换地转换成的
duration
。例如,
lcm_type_t<milliseconds, nanoseconds>
的类型为
milliseconds
。这样的转换不会溢出。
template <class Duration0, class ...Durations>
struct lcm_type;
template <class Duration>
struct lcm_type<Duration>
{
using type = Duration;
};
template <class Duration1, class Duration2>
struct lcm_type<Duration1, Duration2>
{
template <class D>
using invert = std::chrono::duration
<
typename D::rep,
std::ratio_divide<std::ratio<1>, typename D::period>
>;
using type = invert<typename std::common_type<invert<Duration1>,
invert<Duration2>>::type>;
};
template <class Duration0, class Duration1, class Duration2, class ...Durations>
struct lcm_type<Duration0, Duration1, Duration2, Durations...>
{
using type = typename lcm_type<
typename lcm_type<Duration0, Duration1>::type,
Duration2, Durations...>::type;
};
template <class ...T>
using lcm_type_t = typename lcm_type<T...>::type;
lcm_type_t<Duration1, Duration2>
,而不必担心溢出,然后进行比较。
lcm_type_t
,并且由于截断损失,请比较相等。因此,我更喜欢使用
double
的解决方案,但是在工具箱中也添加
lcm_type
是一件好事。
关于c++ - 我如何才能真正使用std::chrono类型而不冒溢出和未定义行为的风险?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54056353/
注意:根据 ECMAScript5.1, section 15.1.1.3 , window.undefined 是只读的。 现代浏览器正确地实现了这一点。例如:Safari 5.1、Firefox
我用谷歌搜索,检查了所有常见的响应。这些脚本似乎顺序正确(它们在 the demo 中以相同的顺序工作)但由于某种原因,当我尝试实现它时,我得到了错误。 我有一个 paste bin用我完整的页面代码
我有以下代码: simpleExample.html: Simple example Open the Console. js/simpleExampleJS.
所以我对 typescript 很陌生。 这是我的 tsconfig.json 文件的样子, 我什至不知道那些“例子”是从哪里来的 这是我在浏览器中遇到的错误 这是我的 package.json 最佳
我被 TypeScript 错误困住了: Failed to compile. undefined TypeScript error in undefined(undefined,undefined)
我已将 onlcick 事件附加到表单的提交按钮以覆盖默认的 POST 请求,但在使其正常工作时遇到了一些问题。 我想要的是点击添加到购物车的商品,但只显示模式确认而不刷新页面。 这段代码在我的静态示
我已经完成了这个link .但是给定的解决方案并没有解决我的问题。所有经验丰富的人都建议使用 getActivty().getApplicationContext()。但我使用的是普通类(class)
我有一个应用程序,其中 webpack 配置为模块 bundler ,babel 作为我的 js 编译器。全部都在 Node 引擎上。我设置当我运行 npm run dev 时,将会发生以下流程: w
我正在尝试在浏览器中呈现网址的 JSON 数据,但它在 div 中显示为 undefined, undefined .当我将其响应放入console.log时对象及其数据出现,因此它出现在控制台和浏览
为什么我会收到 Cannot invoke an object which is possibly 'undefined'即使在我检查了 func 之后,Typescript 也会出错引用不是未定义的
我想使用airbnb的eslint修改我的代码结构。我已遵循 eslint-config-airbnb 中给出的说明。启动命令后npm run lint,结果由 'fetch' is not Defi
这个问题在这里已经有了答案: What is the consequence of this bit of javascript? (4 个答案) 关闭 9 年前。 我看到一些 jQuery 脚本嵌
我一直收到这个 pouchDB 错误,我不知道这是怎么回事。 Error: connect ENFILE 127.0.0.1:5984 - Local (undefined:undefined)
import os from os.path import abspath, dirname import sys # Set up django project_dir = abspath(dirn
在 javascript 中,要检查变量是否从未创建过,我们只需执行 if (typeof MyVariable !== "undefined"){ ... } 我想知道如何在 CoffeeScrip
我正在尝试编译 FreeLing,它使用 CMake 来检测 Boost。这是负责它的代码: find_package(Boost COMPONENTS regex filesystem thre
我收到“JQUERY 未定义”错误。你有什么想法吗(代码如下)。 $(document).ready(function() { window.print();
无论我是否将 jQuery $.ajax 调用放入 $(document).ready(function() { 中,我都会收到此错误。这是在 ASP.NET MVC .cshtml 文件上.
我正在构建的网站上遇到问题,但数据表不存在加载(在服务器上)但在本地主机(xamp)上工作正常。 Firefox 会抛出错误“$ 未定义”。 我用谷歌搜索了这些错误,我发现一个 friend 的解决方
当我在 $(document).ready 之前明确包含 jQuery 库时,我无法弄清楚为什么它仍然无法识别 jQuery 语法
我是一名优秀的程序员,十分优秀!