【发布时间】:2021-07-21 01:02:17
【问题描述】:
我们正在编写安全关键代码,我希望有一种比[[nodiscard]] 更强大的方法来确保检查 函数返回值被编译器捕获。
[更新]
感谢 cmets 中的所有讨论。让我澄清一下,这个问题可能看起来是做作的,或者不是“典型用例”,或者不是其他人会怎么做。如果这样更容易忽略“你为什么不这样做呢?”,请将其视为学术练习。问题是如果没有将左值分配给函数调用的返回结果,是否有可能创建编译失败的类型。
我知道 [[nodiscard]]、warnings-as-errors 和 exceptions,这个问题询问是否有可能实现类似的东西,即 compile time error ,而不是在运行时捕获的东西。我开始怀疑这是不可能的,因此非常感谢任何解释原因。
约束:
- MSVC++ 2019
- 不依赖警告的东西
- Warnings-as-Errors 也不起作用
- 不断运行静态分析是不可行的
- 宏没问题
- 不是运行时检查,而是被编译器捕获
- 不基于异常
我一直在思考如何创建一个类型,如果它没有从函数返回中分配给变量,编译器会标记一个错误。
例子:
struct MustCheck
{
bool success;
...???...
};
MustCheck DoSomething( args )
{
...
return MustCheck{true};
}
int main(void) {
MustCheck res = DoSomething(blah);
if( !res.success ) { exit(-1); }
DoSomething( bloop ); // <------- compiler error
}
如果通过类型系统证明这样的事情是不可能的,我也会接受这个答案;)
【问题讨论】:
-
如果检查返回值那么重要,为什么不抛出异常呢?
-
虽然“鼓励”编译器在返回值被丢弃时使用
[[nodiscard]]发出警告,但大多数编译器可以配置为将警告视为错误并停止编译。 Microsoft 编译器和 IDE 支持这样的选项。 -
另外,请记住,任何(尝试)强制调用者检查返回值的方法都可以被调用者明确规避。例如,如果编译器由于
[[nodiscard]]而发出警告/错误,调用者仍然可以通过简单的强制转换(即(void)DoSomething(bloop))击败编译器提交。有一点你必须依靠其他程序员阅读文档并做需要做的事情。 -
如果一个警告变成了一个错误,那就是一个真正的错误,会导致构建失败。为什么这是个问题?这不是你想要的吗?
-
DoSomething 可以采用两个参数: lambda 调用成功, lambda 调用失败。这样,调用者负责显式处理成功和失败的情况(即使处理程序是空操作)。
标签: c++ static-analysis type-systems