通过方法接口表达C ++参数的用法

时间:2009-01-25 23:05:34

标签: c++ interface arguments

在C ++中是否有一种表达参数用法的常用方法?我想暗中告诉我的班级的消费者他们传递的参数将如何被类使用。

示例:

  1. 我拥有你的论点(将清理它)
  2. 我会在我的一生中提到你的论点(所以你不应该在我活着的时候删除它)
  3. 我将仅在构造期间使用您的参数,并且不会持有参考
  4. 使用方法声明是否有一种表达这些内容的常用方法?我认为在第一种情况下,std :: auto_ptr会有意义。在第二种情况下,我通常会使用一个指针来避免有人从堆栈中传递一个值,这会使我的引用很快失效,或者是shared_ptr。在第三种情况下,我引用了允许来自堆栈的值。

    你是如何处理的?还有必要在这里依赖智能指针,或者只是通过某种方式使用裸引用和指针来表达这些事情吗?

7 个答案:

答案 0 :(得分:6)

我们的团队与您建议的团队具有相似的编码约定:

1 - auto_ptr参数表示该类将控制对象的内存管理。 (我们不会使用这么多。)

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

3 - 普通参考意味着该参数仅用于通话期间。

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

答案 1 :(得分:3)

我不知道是否有一个共同的习语,但我知道我提供此信息的一种确定方式是接口标题中的注释。班级的用户不会总是阅读它们,也不会永远记住它们,而且它们会比你眨眼更快地搞砸它们,但信息会在那里。

现在,正如所说的那样,我也反对保持对系统其他部分所拥有的东西的引用。重构并不总是实用(或合理),以便你的类拥有所有东西(或者在方法调用返回后不保留引用),但它是最安全的方法,并且任何一个都更容易让调用者理解。

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

答案 2 :(得分:2)

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

答案 3 :(得分:2)

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

我建议将其放入方法名称或参数名称的命名法中,因为至少在自动完成窗口中可以看到它。这很难看,但它通过以下方式传达了信息:)

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

答案 4 :(得分:2)

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

我可以互换地使用const引用和值参数。 (如果值大于寄存器,我使用引用 - 这只是一个优化。)如果需要,被调用者将按值复制,因此可以立即销毁参数。 (案例3。)

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

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

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

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

答案 5 :(得分:2)

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

Y.take_ZZZ(x)

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

Y.own_ZZZ(x)

类似于take; 调用者将x的所有权赋予Y,但调用者可以继续引用x 并期望Y不会立即删除x (至少存在Y并且假设Y将至少在调用者知道Y的整个上下文中存在)。 通常Y在Y被销毁之前不会删除x(尽管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)

使用checkout,Y为调用者提供对x的独占访问权限,直到调用者将其签入为止。

x = Y.create_ZZZ()

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

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

答案 6 :(得分:1)

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

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

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