我的函数应该接受指针还是智能指针?

3

我开始使用 std::unique_ptr,例如:


unique_ptr<TFile> myfile( TFile::Open("myfile.root") );

替代

TFile * myoldfile = TFile::Open("myoldfile.root") ;

现在我不确定我的函数应该长成什么样子。我认为问题的一部分可能是我的代码还不够复杂,所以尚未出现任何问题,但我希望现在就做对,以免在事情变得更加复杂时陷入困境。

我的旧代码:

double interestingResult( TFile * input )
{...}

这段代码并没有实际修改TFile,但不能使用const关键字,因为它调用了一些非const的TFile函数。

我仍然可以通过以下方式调用:

myResult  = interestingResult( myfile.get() );

这似乎不是很用户友好。(我认为建议在这里:https://dev59.com/nlXTa4cB1Zd3GeqP0EUK#5325560。)

或者我可以修改我的函数看起来像:

double interestingResult( unique_ptr<TFile>& input )
{...}

强制用户始终使用unique_ptr。

或者我可以通过编写以下代码来同时支持两种方式:

double interestingResult( unique_ptr<TFile>& input )
{ return interestingResult( intput.get() ); }

但我在别人的代码中没有看到这种做法。

在这种情况下,标准的方法是什么?

我认为这个答案 (https://dev59.com/zWkw5IYBdhLWcg3ws833#9700189) 意味着我应该接受引用,因为我不希望 myfile 是空值。但库函数 TFile::Open 总是返回指针,所以直接将其传递到函数中而不需要额外的解引用似乎是很自然的做法。

道歉的附言:我放弃了尝试弄清楚是否应该在StackOverflow或CodeReview上询问或者干脆不问,但如果这不是适当的地方,请指出适当的地方。

4个回答

4
你所指的答案是正确的。
如果你有一个函数应该作用于任何现有的TFile实例,并且没有理由接受NULL指针作为有效参数,而且函数参数不具有所有权,那么应该使用TFile&作为参数类型(在可能的情况下使用TFile const&)。被传入的对象是否由调用者通过指针(带或不带所有权)持有对该函数不应产生影响。
你可以选择使用TFile*参数,但这至少会在传递NULL的有效性上产生歧义,因此可能会在将来引起问题。
如果你使用unique_ptr参数,则会将对象的所有权彻底地传递到函数中。当调用返回时,调用者将获得一个空的unique_ptr。
如果你使用unique_ptr&参数,则表明该函数可以选择接管对象的所有权或者将其留给调用者。这是相当不寻常的。 unique_ptr const&参数可以像TFile*一样使用,但强制调用者拥有该对象并使用unique_ptr管理它。为什么要强加这样的要求呢?当然,这(以及unique_ptr的其他用途)都必须处理NULL情况。

3

在参数列表中接受智能指针的问题在于你要规定调用者只能使用哪种类型的智能指针。例如,通过使用unique_ptr,你防止了调用者使用shared_ptr。

对于你的情况,我建议使用引用参数。我也经常看到使用普通指针。主要是确保你的函数在返回后不会尝试持有一个引用/拥有对象 - 即它不会后来负责释放内存。


2

无论是引用TFile&还是指针TFile *都可以。

有些人会告诉你,当空指针是函数的无效输入时,你“应该”使用引用。这些人会在尝试使用从C语言继承下来的标准函数如std::strlenstd::memcpy等时变得困惑和愤怒。我认为,虽然使用引用来自说明需要引用参考对象非常好,但使用既与引用一致又与指针一致的API也是相当好的。

有些人会告诉你,“不应该”使用非const引用参数,而更喜欢使用指针。他们会在尝试使用像std::swap之类的标准函数时变得困惑和愤怒,因为对于C程序员来说,看起来像按值传递,所以它“不应该”修改输入。

只要你不与上述两种人一起工作,你可以自己做出选择。


在 NULL 无效值的情况下使用指针类型通常会导致维护问题。最好的情况是,使用 NULL 会成为运行时问题 - 需要重复检查并提供信号错误的通道。否则,如果存在一个调用路径,其中 NULL 可以滑过,则会导致崩溃或更糟的情况。如果这是项目的风格或者你遇到了非 const 引用的恐惧,那么你必须这样做 - 但你应该意识到后果。FYI:我不害怕在 C(-style) 代码中使用 strcpy,但当我有选择时,我会使用字符串类而不是裸 C 字符串。 - JoergB
1
@JoergB:我没有观察到那些常规维护问题在使用指针的代码中更糟糕。那种不费心查看文档中 null 是否是有效输入的人(即在非常糟糕的一天里几乎任何人)也不费心在解除引用指针之前检查 null。所以他们只是将 *p 传递给您的函数,该函数采用引用,并且有时 p 在他们的代码中为 null,需要有人发现并修复它。 - Steve Jessop
2
顺便说一句,当我尝试使用需要指针的函数但作者没有明确说明空输入是否有效时,我会感到困惑和愤怒,因为按照惯例,如果函数需要指针,则null是有效的。;-) - Steve Jessop
这个回答及其评论似乎涵盖了所有内容。我的理解是:除非您想要拥有所有权,否则永远不要接受智能指针。最好接受引用。如果其他人正在使用指针执行类似的功能,保持一致可能更好。 - paco_uk

1

这取决于情况,但在函数中使用原始指针(或对象的引用)更为推荐,因为函数不会拥有指针。

而且,如果有一天您决定使用 shared_ptr...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接