我知道static_assert
在编译时会做出断言,并且assert
- 在运行时会做出断言,但实际上有什么区别?据我了解,在内心深处,它们是代码片段,例如
if (condition == false) exit();
- 有人可以给我一个例子,只
static_assert
在哪里可以工作,或者只assert
在哪里工作? - 他们能做一些简单的
if
语句做不到的事情吗? - 使用它们是不好的做法吗?
你问了三个问题,所以我会试着回答每个问题。
static_assert
在哪里可以工作,或者只 assert
在哪里工作?static_assert
有利于在编译时测试代码中的逻辑。assert
非常适合在运行时检查一个您期望应该始终有一个结果的案例,但在未预料到的情况下可能会以某种方式产生意想不到的结果。例如,您应该仅assert
用于确定传递给方法的指针null
是否似乎永远不会发生。static_assert
不会抓住那个。
if
语句做不到的事情吗?assert
可用于中断程序执行,因此您可以使用if
适当的错误消息,然后停止程序执行以获得类似的效果,但assert
在这种情况下更简单一些。static_assert
当然仅对编译问题检测有效,而if
必须在编程上有效并且不能在编译时评估相同的期望。(然而,Anif
可用于在运行时吐出错误消息。)
一点也不!
static_assert
意味着使编译失败并显示指定的消息,而传统assert
意味着结束程序的执行。
好吧,我咬一口:
仅static_assert
当您希望编译在违反静态条件时无法成功停止时才有效:static_assert(sizeof(void*) != 3, "Wrong machine word size");
* 只有动态断言才能捕获动态条件:assert(argc == 1);
简单if
的语句必须有效且可编译;静态断言会导致编译失败。
不。
*) 一个实际的例子可能是防止滥用通用模板结构,例如int x; std::move<int&&>(x)
.
使用它们是不好的做法吗?
如果被滥用,是的,尤其是assert
。
一种滥用是依赖于这些assert
声明是活跃的。你永远不应该依赖assert
做任何事情,因为代码可以用NDEBUG
定义的方式编译,然后assert
什么也不做。生产代码通常使用NDEBUG
定义进行编译,以确保这些assert
语句消失。
除非您正在编写一个不会超过一两天的一次性程序,否则您不应该使用它来验证用户输入。用户并不关心代码在哪里出错,而且打印出来的消息在许多用户看来就像是一门外语。它没有告诉用户如何修复错误。从设计上讲,这也是非常无情的。响应用户输入错误而发出的消息应该是告诉用户如何解决问题的消息。消息后的最佳操作是为用户提供修复错误的方法。如果不能这样做,并且唯一可行的响应是结束程序,则程序应该干净地终止。按照设计,assert
不会导致完全关闭。它调用abort()
而不是exit()
.
许多机器上的一个后果abort()
是产生核心转储。对于程序员来说,核心转储是一个很好的错误消息。通过核心转储,程序员可以使用调试器详细查看问题所在。缺点abort()
是东西没有清理干净。中止“终止程序而不执行自动或静态存储持续时间的对象的析构函数,并且不调用传递给的函数atexit()
。”
底线:可以(而且很好)用于assert
测试编程错误,但只能在非生产环境中使用。使用其他东西来测试用户错误。
static_assert
是一个编译器指令。它允许您在编译时检查类型信息。它将导致编译失败并产生错误消息,在大多数 IDE 中会被捕获并显示在 IDE 的错误窗口中。
static_assert(sizeof(int) == 4,"int should be 4 bytes");
assert
用于运行时,您可以检查变量的值。如果断言失败,则断言将触发。这将导致在某些操作系统的运行时出现错误消息框(依赖于断言实现)
assert(("mypointer should never be null!", mypointer != nullptr));
应该提到的是,尽早发现错误很重要。程序员想知道什么时候首先出现问题,而不是由原始问题引起的数百个问题。如果代码计算出错误的值,然后在后续计算中使用它,那么所有这些计算都是错误的。找到问题的早期原因可以防止程序员不得不及时追溯错误。
对于运行时和编译都是如此。Assert 有助于运行时,而 static_assert 有助于编译。static_assert 对编译时检查很有用的示例,以确保某些标头的版本可能等于其余代码需要或经过测试的版本。如果 static_assert 告诉您标头版本已更改,那么它比试图弄清楚为什么所有这些编译错误都由更改的标头触发要有用得多。它在编译过程中尽早发现问题。
static_assert 的另一个用途是检查编译是否使用正确的编译器开关完成。例如,Microsoft 的编译器使用 /J 来表示 char 是无符号的 8 位值,而不是有符号的。如果代码需要,可以在编译时检查。