关于向c++例程传递参数时使用指针/引用的建议

Advice on the use of pointers/references when passing arguments to C++ routines

本文关键字:指针 引用 c++ 例程 参数      更新时间:2023-10-16

我在嵌入式环境(实际上是c++的一个子集)中使用c++,并且想要一些关于在向例程传递参数时使用指针/引用的建议。

一个常见的技巧是"尽可能使用引用,必要时使用指针"。我相信这与避免空指针有关。

但是,当前的编程指南禁止使用引用。

请参考下面的讨论,看看你是否同意。

伯特:我们应该在适当的时候利用引用传递参数(内置空指针保护)。这将产生更小、更健壮的代码。

厄尼:我不同意。使用引用隐藏了可能被更改的参数,因此,当您检查代码或查看特定函数正在做什么时,您现在必须查看它调用的每个函数,以及它们调用的每个函数,以查看您传入的任何参数是否可能被更改。然而,如果你使用指针,那么你知道如果你传入一个指针,它可能会被改变。如果你没有传递一个指针,那么你就知道它没有被改变。这种易于维护的特性值得解决NULL指针问题。对于引用,仅仅因为你没有NULL指针问题,并不意味着对象已经被正确初始化,并且你有良好的数据。

伯特:可以通过将输入参数(引用)标记为"const"来减轻这种担忧。(这类似于Google的编码风格。)那么您就知道其他参数是可以修改的。可修改的参数可以以"r"开头,这在前面的指导方针中是允许的。(当Visual Assist等工具对输入/输出进行颜色编码以帮助提供视觉提示时,不要感到惊讶。)

厄尼:将参数(引用)标记为"const"并不能缓解这个问题。因为当你在一个层次上有人在调用这个函数时,你只有一个常规变量,比如nSomeNumber。你必须去函数原型看看变量是否可能被改变。或者,你必须将鼠标悬停在函数上才能看到原型。所以你不能只是快速扫一扫代码就知道可能会发生什么。此外,有些时候你没有颜色编码,比如在代码审查期间的Beyond Compare中,你不能轻松地悬停或转到原型。我强烈反对使用引用,因为它们使代码的维护和可读性变得困难,而且容易出错;你得到的错误不是简单的检测NULL指针问题,它们是逻辑错误,其中一个值被设置在函数之上并作为引用传递给函数,然后在函数被调用后使用该值,而不是期望它改变。

Grover:仅供参考,Google允许const引用作为参数。据推测,这是为了节省复制对象的成本。Google不允许简单引用参数。如果要更改对象,则通过指针传递它。http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Reference_Arguments

一个常见的技巧是"尽可能使用引用,必要时使用指针"。我相信这与避免空指针有关。

这是一个很好的建议,是的,避免空指针是原因(它也更容易阅读,因为你不需要不断取消引用,或使用->)

Grover:仅供参考,Google允许const引用作为参数。据推测,这是为了节省复制对象的成本。Google不允许简单引用参数。如果要更改对象,则通过指针传递它。

我可以理解反对使用非const引用的理由。在这种情况下,Google的风格指南是最好的方法(输入使用const引用,输出使用指针)。不使用const引用作为输入简直是疯了:你要么必须按值传递,这将非常慢,要么通过指针传递,这将需要大量的地址获取和解引用(更不用说无意义的空指针检查)。这个会使代码更加难以读懂,而不是担心修改的引用。

我的建议是引用总是const(像谷歌风格),除非从函数的任务中可以明显看出参数最终可能在函数内部被修改。在我看来,这应该只发生在所有其他方式都不那么可读的时候,也就是说,你通常应该尽可能地保持函数的"功能性",接受const参数并返回其他东西。这取决于c++的这个子集有多大,这应该不是一个问题:你可能会试图在一个函数f中改变的可变状态信息几乎总是可以以一种方式组织,使这个信息驻留在f是成员的c类中,然后你可以进一步分离"修改函数"answers"纯函数",这样你的函数最终大多是这两种形式

class c;
ret_T f0(const arg1T &, const arg2T &, ...);
ret_T c::f1(const arg1T &, const arg2T &, ...) const;  // pure functions
void c::f3(const arg1T &, const arg2T &, ...);       // modifying functions
c &c::f2(const arg1T &, const arg2T &, ...){
   ...  return *this;
}

显然,这并不总是可能的,或者至少不是总是可行的,但它经常是,所以给那些不适合这种模式的函数(即返回一些重要的修改状态的函数)一个漂亮的长描述性名称不会有什么伤害,以清楚地表明它们会。