5

有没有一种通用的方法来表达 C++ 中参数的用法?我想隐含地告诉我班级的消费者他们传递的参数将如何被班级使用。

例子:

  1. 我拥有你的论点(将清理它)
  2. 我会在我有生之年参考你的论点(所以你不应该在我还活着的时候删除它)
  3. 我只会在构建过程中使用您的论点,并且不会提供参考

有没有一种通用的方法来简单地使用方法声明来表达这些事情?我认为在第一种情况下 std::auto_ptr 是有意义的。在第二种情况下,我通常使用一个指针来避免有人从堆栈中传递一个值,这会使我的引用快速失效,或者是一个 shared_ptr。在第三种情况下,我引用以允许来自堆栈的值。

你如何处理这个问题?这里是否有必要依赖智能指针,或者可以通过某种方式简单地使用裸引用和指针来表达这样的事情?

4

7 回答 7

6

我们的团队与您建议的编码约定类似:

1 - auto_ptr 参数意味着该类将控制对象的内存管理。(我们用的不多。)

2 - shared_ptr 意味着该类可能会长时间使用该参数,特别是可能会将其自己的 shared_ptr 存储到对象中。

3 - 纯引用意味着该参数将仅在调用期间使用。

我们将此视为编码标准。这不是我们为每个电话记录的内容。

于 2009-01-25T23:50:43.353 回答
3

我不知道是否有一个常见的习惯用法,但我知道我提供此信息的一种可靠方式是在接口标题中添加注释。课程的用户不会总是阅读它们,不会总是记住它们,而且他们会比你眨眼更快地把它们搞砸,但信息会在那里。

现在,话虽如此,我也反对保留对系统其他部分拥有的东西的引用。重组以使您的类拥有所有内容(或在方法调用返回后不保留引用)并不总是实际(或明智),但这是最安全的做事方式,并且任何一种方式都更容易让调用者理解。

保留引用的最大问题是您的调用者永远不会记得他们不允许销毁这些东西,并且您最终会以“使用已删除对象”类型失败而告终。

于 2009-01-25T23:20:44.240 回答
2

也许我错过了你的问题,但如果你的头文件中的方法原型设置正确,那么就可以了。
“隐式”用户将知道您给定的方法只接受对参数的引用,或者给定的参数是只读的(const)......等等......

于 2009-01-25T23:17:17.163 回答
2

虽然文档是唯一的答案,但不幸的是它不是一个有用的答案。我一直在做的研究表明,许多客户从未阅读过他们正在使用的方法的文档。

我建议将其放入您的方法名称或参数名称的命名中,因为至少在自动完成窗口中是可见的。这很丑陋,但它可以通过:)

在我自己的工具(用于 Java/Eclipse)中,我有一个标签,允许我在用户需要了解有关参数的重要信息时向用户宣布。

于 2009-01-25T23:27:46.583 回答
2

我不使用使用 boost 或 STL 的代码,因为我不使用特别支持它们的系统,但我发现以下标准很有用......

我交替使用 const 引用和值参数。(如果值大于寄存器,我使用引用——这只是一种优化。)如果需要,被调用者将按值获取副本,因此可以立即销毁参数。(案例 3。)

我使用 const 指针来指示输入是按引用的,并且被调用者将按引用获取副本。参数的生命周期必须超过被调用者的生命周期。(案例 2。)

我使用非常量指针来指示输入是按引用的,并且如果需要,被调用者将修改指针。在一般情况下,故意未定义参数的寿命。(即案例 2 或 3。)

我自己不使用非常量引用,纯粹是因为在调用点的语法上并不明显,但这只是我个人的倾向。我有我的理由,但这并不意味着其他人必须同意!因此,正如我在 const 案例中所描述的那样,可以有用地使用引用/指针的区别来指示寿命。在这种情况下,也许指针 = 案例 2,引用 = 案例 3。

我通过评论指出案例 1(被调用者取得所有权);这在我的代码中很少见,我不太担心。

于 2009-01-26T02:07:56.337 回答
2

我使用以下方法前缀来表示对象所有权。所有权意味着删除的责任。

Y.take_ZZZ(x)

调用者将 x 的所有权授予 Y,调用者不得进一步访问 x。(因为 Y 甚至可以立即删除 x)。

Y.own_ZZZ(x)

类似于采取;调用者将 x 的所有权授予 Y,但调用者可能会继续引用 x 并期望 Y 不会立即删除 x(至少只要存在 Y 并且假设 Y 将至少存在于调用者知道的整个上下文中)是)。通常 Y 不会删除 x,直到 Y 被销毁(尽管 Y 可能会转移所有权)。

Y.know_ZZZ(x)

调用者提供了一个指向 x 的指针/引用(调用者自己可能拥有也可能不拥有 x),但 Y 不拥有 x 的所有权。Y 会期望 x 会一直存在。

x = Y.provide_ZZZ()

x 是 Y 拥有的对象。Y 返回对对象的引用 (&),以便调用者可以“知道”它。对象在需要之前可能最初是空指针,Y 可能在需要之前不会创建对象。无论 x 是否是动态分配的,对调用者都是隐藏的,Y 会做任何需要的事情来返回对要提供的对象实例的引用。只要 Y 存在,x 就会保持实例化。有时我会提供一个相应的方法 Y.done_with_ZZZ(x) 以便调用者可以告诉 Y 它已经完成可以删除 x。

x = Y.give_ZZZ()

Y 将 x 让给调用者并且不再引用它。然后调用者将拥有 x 并负责将其删除或将其提供给另一个对象。

x = Y.lend_ZZZ()

Y 向调用者提供指向 x 的引用/指针(与 know_ZZZ 相反) Y 保留所有权。(类似于提供,但 Y 不实例化 X,因此它要么有 x 并返回引用(指针),要么没有并返回 null。

x = Y.check_out_ZZZ() and Y.check_in_ZZZ(x)

通过结帐,Y 为调用者提供对 x 的独占访问权限,直到调用者将其签入。

x = Y.create_ZZZ()

Y 将创建 x 并立即将其交给调用者(工厂函数)。

所有权可以通过使用智能指针进一步加强,但通常我使用这些命名约定而不使用智能指针,除非有更复杂的所有权事务序列,所有权范围不是很本地化,或者对象将被多个对象引用(已知)。

于 2009-01-26T21:07:37.253 回答
1

如果您正在寻找清晰度,文档是处理此问题的一种好方法。当然,这是假设人们关注您的文档。

除了使用具有已知使用模式的现有类之外,您还可以创建自己的类。使用编译器可以从普通参数自动生成的类(当然,使用您将编写的运算符),您可以更准确地指定合同,而不会使传递参数变得更加困难。这有一些缺点(额外的类,更多的层供用户查看和理解,命名职责),但这是一个需要考虑的选项。

如果您处于可以使用 IntelliSense 的环境中,请确保参数描述中包含必要的信息。这可以使您免于任何其他步骤。

于 2009-01-25T23:15:29.993 回答