例如,如果我有结构FooSpec
:
struct FooSpec { /* lots of data */ };
将以下以下作为重载函数提供是不好的做法吗?或者我应该选择一个并坚持下去?
Foo *createFoo(const FooSpec *spec) { /* ... */ }
Foo *createFoo(const FooSpec &spec) { return createFoo(&spec); }
两者都会导致意外问题吗?
答案 0 :(得分:21)
应该只有一种方法来做某件事。这将使代码更清晰。因此,您应该只选择一个,具体取决于语义:
如果nullptr
是一个有意义的值传递给createFoo
,则声明该函数采用指针。
如果不应将nullptr
传递给createFoo
,则将参数声明为引用,以使编译器对尝试传递nullptr
的人大喊大叫。< / p>
现在你的代码的用户将会“啊,我可以将null传递给该函数,很酷!”或者“好的,这个功能需要一个实际的对象才能正常工作”。
在整个项目中坚持这一惯例,使代码的界面更加连贯。
或者正如WhozCraig所说的那样,
选择合适的模型并告诉客户“这是您的界面。”
答案 1 :(得分:4)
我可以想到这样做的一个有用的原因。
Foo*
版本可以检查null,处理该情况,如果不使用引用案例。
Foo&
无法检查是否为空。
这让调用者说“我知道这不是空的,因为我检查了”,在函数中保存了一个分支。
然而,一旦该方法的成本通过非常低的阈值,这种好处(保存分支)是毫无意义的。
答案 2 :(得分:3)
软件代码库不是静态对象,它根据使用它的人的需要发展†。如果一个令人困惑的界面是“不好的做法”(我宁愿说这是一件愚蠢的事情),代码库最终可能会因为重构和代码改进而发展。
在这种情况下,如果您正在迁移编码约定以使用引用而不是使用const指针(或者相反,但这对我来说没有多大意义),那么实践并不错。这里的不良做法可能是做出这些改进而不是记录它,而其他人不知道这些方法中的一种被弃用,或者只是使用哪种方法。
还有可能使用const指针传递nullptr_t
(或NULL
指针为像我这样的旧计时器。我不确定这有什么好处,因为你可以在他们的参数上重载方法,但是在更改API的上下文中它是有意义的。
†它活着!!!