C++ 核心准则边译边学 哲学篇.6:What cannot be checked at compile time... 运行期检查编译期不能检查的内容

源网址:CppCoreGuidelines

原因

在程序中留下难以检测的错误会导致崩溃和错误结果。

注意

理想情况下,我们在编译期和运行期捕获程序的所有错误(除了程序的逻辑错误)。在编译期捕获所有错误是不可能的,但是运行期捕获所有遗留的错误通常是难以承受的。但是在资源充足的条件下(分析程序、运行时检查、机器资源、时间),我们应该努力编写原则上可以检查的程序。

反例

// separately compiled, possibly dynamically loaded
extern void f(int* p);

void g(int n)
{
    // bad: the number of elements is not passed to f()
    f(new int[n]);
}

这里,有一个至关重要的信息(元素的数量)被彻底掩盖了,这导致静态分析已经不可行,而且当f()是一个二进制程序接口(ABI)时动态检查可能非常困难,因此我们无法“检测”该指针。我们可以将有用的信息嵌入到空闲的存储空间,但是这需要对系统甚至编译器进行全局更改。我们这里的设计使错误检查非常困难。

反例

我们当然可以和指针一起传入一个元素数量:

// separately compiled, possibly dynamically loaded
extern void f2(int* p, int n);

void g2(int n)
{
    f2(new int[n], m);  // bad: a wrong number of elements can be passed to f()
}

相比于仅仅传递指针并且依赖于一些(未说明的)习惯来了解或者发现元素的数量,传入元素数量参数是更好(也更常见)的做法。然而(像代码里那样),一个简单的拼写错误会导致一系列严重的错误。f2()的两个参数的关系是约定俗成的,而不是明确的。
此外,这样暗示了f2()应该delete他的参数(或者使调用者犯其他错误?)

反例

标准库资源管理指针指向对象时无法传递大小:

// separately compiled, possibly dynamically loaded
// NB: this assumes the calling code is ABI-compatible, using a
// compatible C++ compiler and the same stdlib implementation
extern void f3(unique_ptr<int[]>, int n);

void g3(int n)
{
    f3(make_unique<int[]>(n), m);    // bad: pass ownership and size separately
}

例子

我们需要将指针和元素数量作为一个整体对象传递:

extern void f4(vector<int>&);   // separately compiled, possibly dynamically loaded
extern void f4(span<int>);      // separately compiled, possibly dynamically loaded
                                // NB: this assumes the calling code is ABI-compatible, using a
                                // compatible C++ compiler and the same stdlib implementation

void g3(int n)
{
    vector<int> v(n);
    f4(v);                     // pass a reference, retain ownership
    f4(span<int>{v});          // pass a view, retain ownership
}

这个设计将元素数量作为对象的一部分,这样不太可能出错而且动态(运行期)检测总是可行的,反之则不然。

例子

我们如何一起转让所有权和需要检验的信息?

vector<int> f5(int n)    // OK: move
{
    vector<int> v(n);
    // ... initialize v ...
    return v;
}

unique_ptr<int[]> f6(int n)    // bad: loses n
{
    auto p = make_unique<int[]>(n);
    // ... initialize *p ...
    return p;
}

owner<int*> f7(int n)    // bad: loses n and we might forget to delete
{
    owner<int*> p = new int[n];
    // ... initialize *p ...
    return p;
}

例子

  • ???(PS:是说没有例子的意思吗?)
  • (PS:这个好难懂,我猜测是表达想通过一个例子,“展示当传递多态基类的接口实际上知道他们需要的类型时,如何避免可能的类型检查?或字符串作为’自由风格’选项”,附上原文)
    show possible checks are avoided by interfaces that pass polymorphic base classes around, when they actually know what they need? Or strings as “free-style” options

补充

  • 标记(指针,计数)样式的接口(这将标记很多出于兼容性原因无法修复的示例)
  • ???
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值