Re: [讨论] 关于空指标的检查时机

楼主: poyenc (发箍)   2019-09-19 04:43:43
※ 引述《henry8168 (番薯猴)》之铭言:
: 正在工作,在修前人的 code。
: 假设现在有 function F 和 function G,
: function F 内执行的程式码会呼叫 function G 并将某个指标作为参数传入 G
: 想请问一下高手大大们,空指标的检查一般都在:
: 1) function F 要传入该指标到 function G 前
: 2) 收到该指标的 function G 的开头
: 3) 1、2 两者皆要
: 的哪个时机检查最好?
: 又有什么优缺点?
: 因为选方案 1 的话,要是某些时候呼叫 G 前忘记检查就会出事,而且程式码满冗赘的;
: 可是如果用方案 2 的话,在某些情况下,
: 会呼叫 G 的 function F 可能已经存取过该指标,等于先保证不会为空,
: 那 2 的作法就等于每次都多一道检查行为。
: 方案 3 没看过,可能老鸟跟菜鸟没串好 @@?
: 那有约定成俗的 coding rule 吗?
: 一般都怎么写比较好?
这个问题因为没有完整情境所以回答起来会复杂些, 涉及的观念包
含软件验证还有测试, 不过因为这里是语言专版所以小弟尽量把解
说侷限在语言层面上. 首先在将指标做为函式参数时, 你需要先回
答几个问题:
1. 是否允许呼叫端 (caller) 选择性提供引数?
2. 如果不该是选择性提供引数, 那应该由谁来确保它的値并
非 nullptr?
3. nullptr 应该当成合法输入, 还是当成错误处理?
第一个问题完全可以用语法来描述, 譬如使用参考 (reference) 来
表示 caller 必须提供该引数, 而其他情况则是用指标.
剩下的问题如果你非得用指标不可, 那该谁来检查指标是否为
nullptr 呢? 答案是 caller 和被呼叫端 (callee) 有可能都要检
查, 只不过检查的方式取决于你想表达的语意, 可粗略分为以下 3
种:
1. caller 要确保指标非 nullptr
这时候参数非 nullptr 即是呼叫函式的前置条件 (pre-
condition), nullptr 在这个情况被当成不合法的输入,
但是 callee 不用对这个非法输入做特别处理, 程式当掉
时会是 caller 的责任. 通常前置条件在 callee 会用断
言 (assertion) 来宣告, 或是另外写文件来描述. 你可
以把断言看做是检查的一种, 但是 caller 在呼叫前对应
的检查还是免不了. 标准函式库的 strlen() 就是其中一
个例子.
2. callee 要确保指标非 nullptr
nullptr 在这个情况被当成合法的输入, 但是给了 nullptr
会有特别的行为, 可能不做事, 回传错误代码 (代码是用来
说明为什么 callee 无法履行义务), 或是代表操作结束.
通常 callee 会用 if 来做处理, 标准函式库的 strtok()
是其中一个例子. caller 在遇到函式有特别行为时, 也许需
要反过来检查是否因为引数给 nullptr 造成这个差异.
3. caller 和 callee 都不需要做 nullptr 检查
nullptr 在这个情况被当成合法的输入, 但如果是合法输入
, 我们又应该如何去使用它呢? 答案是: 不需要. 通常不需
要检查的情况会发生在参数间有相依性存在的时候, 例如我
们想印出整数阵列里的所有元素値, 可以用下面的 print()
函式, 引数组合完全合理:
void print(const int* array, size_t size) {
for (size_t idx = 0; idx < size; ++idx) {
std::cout << array[idx] << " ";
}
std::cout << std::endl;
}
print(nullptr, 0); // do nothing
作者: nickchen1202 (Nickchen Nick)   2019-09-19 07:32:00
想问一下那个print函数如果第二个参数非0会怎么样
作者: Lipraxde (Lipraxde)   2019-09-19 08:17:00
那第一个参数就不该传 nullptr 吧?
作者: henry8168 (番薯猴)   2019-09-19 16:38:00
谢谢 我想我会倾向callee自行处理nullptr的选项

Links booklink

Contact Us: admin [ a t ] ucptt.com