C++核心准则边译边学-I.30 封装必要的违反

网友投稿 534 2022-10-25

C++核心准则边译边学-I.30 封装必要的违反

C++核心准则边译边学-I.30 封装必要的违反

I.30: Encapsulate rule violations(封装必要的违反)

Reason(原因)

To keep code simple and safe. Sometimes, ugly, unsafe, or error-prone techniques are necessary for logical or performance reasons. If so, keep them local, rather than "infecting" interfaces so that larger groups of programmers have to be aware of the subtleties. Implementation complexity should, if at all possible, not leak through interfaces into user code.

为了保证代码简单和安全。有些时候,因为逻辑或者性能上的原因,难看的,不安全,或者易错的技术也是必要的。如果(必须)这样,将它们限定在局部,而不是传染给接口从而导致更多的程序员必须小心处理它们。实现层面的复杂性应该尽可能的不用通过接口影响到用户的代码。

译者注:面向对象的第一个特性:封装的目的之一就是隔离实现和接口。如果实现影响到接口,一个根本原因就是对封装的理解有问题。

Example(示例)

Consider a program that, depending on some form of input (e.g., arguments to ​​main​​), should consume input from a file, from the command line, or from standard input. We might write

考虑依赖某种形式的输入(例如main函数的参数)的程序,假设其输入来自文件,命令行或者标准输入,代码可能这样写:

bool owned;owner inp;switch (source) {case std_in: owned = false; inp = &cin; break;case command_line: owned = true; inp = new istringstream{argv[2]}; break;case file: owned = true; inp = new ifstream{argv[2]}; break;}istream& in = *inp;

This violated the rule against uninitialized variables, the rule against ignoring ownership, and the rule against magic constants. In particular, someone has to remember to somewhere write

这段代码违反了针对未初始化变量的准则,针对忽略所有权的准则和针对魔术常量的准则。通常,某人必须记着在某些写下:

if (owned) delete inp;

We could handle this particular example by using ​​unique_ptr​​​ with a special deleter that does nothing for ​​cin​​, but that's complicated for novices (who can easily encounter this problem) and the example is an example of a more general problem where a property that we would like to consider static (here, ownership) needs infrequently be addressed at run time. The common, most frequent, and safest examples can be handled statically, so we don't want to add cost and complexity to those. But we must also cope with the uncommon, less-safe, and necessarily more expensive cases. Such examples are discussed in [Str15].

我们可以使用带有特殊删除器的unique_ptr来处理这段常见的示例代码,这个删除器对cin不做任何事情,但是这个技术对初学者(很容易遭遇这个问题的人)是有困难的。另外这段示例代码只是某个应该被认为是静态的属性(这里是所有权)需要在执行时处理的更普遍问题的一个例子。一般来说,更多的情况,最安全的示例可以被静态处理,因此我们不想增加额外的代价和复杂性。但是我们也必须处理不常见的,不够安全的和必要的高代价的情况。这样的例子在[Str15]中被讨论。

译者注:[Str15]:we write a class

因此我们写了一个类:

class Istream { [[gsl::suppress(lifetime)]]public: enum Opt { from_line = 1 }; Istream() { } Istream(zstring p) :owned{true}, inp{new ifstream{p}} {} // read from file Istream(zstring p, Opt) :owned{true}, inp{new istringstream{p}} {} // read from command line ~Istream() { if (owned) delete inp; } operator istream& () { return *inp; }private: bool owned = false; istream* inp = &cin;};

Now, the dynamic nature of ​​istream​​ ownership has been encapsulated. Presumably, a bit of checking for potential errors would be added in real code.

现在,作为istream动态特性的所有权已经被包装了。实际的代码可能还需增加一点关于潜在错误的检查。

译者注:删除也好,不删除也好,调用者都不需要关心了。

Enforcement(实施建议)

Hard, it is hard to decide what rule-breaking code is essential困难,很难判断哪种违反规则的代码是必要的。Flag rule suppression that enable rule-violations to cross interfaces标记那些导致规则违反的影响透过接口传播的规则抑制行为。

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:MetalPetal 一个基于Metal的图像处理框架
下一篇:C++核心准则边译边学-F.5 如果函数非常小而且时间敏感,将其定义为inline
相关文章

 发表评论

暂时没有评论,来抢沙发吧~