我了解指针和引用的语法和一般语义,但是我应该如何决定什么时候在API中使用引用或指针比较合适?

当然,有些情况需要其中一个(操作符++需要引用参数),但一般来说,我发现我更喜欢使用指针(和const指针),因为语法很清楚,变量是破坏性传递的。

例如,在以下代码中:

void add_one(int& n) { n += 1; }
void add_one(int* const n) { *n += 1; }
int main() {
  int a = 0;
  add_one(a); // Not clear that a may be modified
  add_one(&a); // 'a' is clearly being passed destructively
}

使用指针,它总是(更)明显的发生了什么,所以对于api和类似的地方,清晰度是一个大问题,指针不是比引用更合适吗?这是否意味着引用应该只在必要时使用(例如操作符++)?其中一种是否存在性能问题?

编辑(过时的):

除了允许NULL值和处理原始数组之外,选择似乎还取决于个人喜好。我接受下面的答案,引用谷歌的c++风格指南,因为他们提出的观点是“引用可能会令人困惑,因为它们有值语法,但有指针语义。”

由于需要额外的工作来清除不应该为NULL的指针参数(例如,add_one(0)将调用指针版本并在运行时中断),从可维护性的角度来看,在必须存在对象的地方使用引用是有意义的,尽管失去语法的清晰性是一种遗憾。


当前回答

任何性能差异都是如此之小,以至于使用不太清楚的方法都是不合理的。

首先,有一种引用通常更好的情况没有提到,那就是const引用。对于非简单类型,传递const引用可以避免创建临时类型,也不会引起您所关心的混乱(因为该值没有被修改)。在这里,强制某人传递指针会导致您所担心的混乱,因为看到地址被获取并传递给函数可能会使您认为值已更改。

无论如何,我基本上同意你的看法。我不喜欢函数接受引用来修改它们的值,而这不是很明显的函数在做什么。在这种情况下,我也更喜欢使用指针。

当需要以复杂类型返回值时,我倾向于使用引用。例如:

bool GetFooArray(array &foo); // my preference
bool GetFooArray(array *foo); // alternative

在这里,函数名清楚地表明您正在从数组中获取信息。这样就不会混淆了。

引用的主要优点是它们总是包含一个有效值,比指针更简洁,并且支持多态,而不需要任何额外的语法。如果这些优点都不适用,就没有理由更喜欢引用而不是指针。

其他回答

我的经验法则是:

Use pointers for outgoing or in/out parameters. So it can be seen that the value is going to be changed. (You must use &) Use pointers if NULL parameter is acceptable value. (Make sure it's const if it's an incoming parameter) Use references for incoming parameter if it cannot be NULL and is not a primitive type (const T&). Use pointers or smart pointers when returning a newly created object. Use pointers or smart pointers as struct or class members instead of references. Use references for aliasing (eg. int &current = someArray[i])

无论您使用哪一种,如果参数不明显,请不要忘记记录函数及其参数的含义。

任何性能差异都是如此之小,以至于使用不太清楚的方法都是不合理的。

首先,有一种引用通常更好的情况没有提到,那就是const引用。对于非简单类型,传递const引用可以避免创建临时类型,也不会引起您所关心的混乱(因为该值没有被修改)。在这里,强制某人传递指针会导致您所担心的混乱,因为看到地址被获取并传递给函数可能会使您认为值已更改。

无论如何,我基本上同意你的看法。我不喜欢函数接受引用来修改它们的值,而这不是很明显的函数在做什么。在这种情况下,我也更喜欢使用指针。

当需要以复杂类型返回值时,我倾向于使用引用。例如:

bool GetFooArray(array &foo); // my preference
bool GetFooArray(array *foo); // alternative

在这里,函数名清楚地表明您正在从数组中获取信息。这样就不会混淆了。

引用的主要优点是它们总是包含一个有效值,比指针更简洁,并且支持多态,而不需要任何额外的语法。如果这些优点都不适用,就没有理由更喜欢引用而不是指针。

在我的实践中,我个人确定了一个简单的规则——对可复制/可移动的原语和值使用引用,对具有长生命周期的对象使用指针。

对于Node的例子,我肯定会使用

AddChild(Node* pNode);

就像其他人已经回答的那样:总是使用引用,除非变量为NULL/nullptr是一个真正有效的状态。

约翰·卡马克在这个问题上的观点也类似:

空指针是C/ c++中最大的问题,至少在我们的代码中是这样。将一个值同时用作标志和地址会导致大量致命问题。在任何可能的情况下,c++引用应该比指针更受欢迎;虽然引用“实际上”只是一个指针,但它有一个非null的隐含契约。当指针转换为引用时执行NULL检查,然后可以忽略此问题。

http://www.altdevblogaday.com/2011/12/24/static-code-analysis/

编辑2012-03-13

用户Bret Kuhns正确地评论道:

c++ 11标准已经完成。我认为是时候在这个线程中提到,大多数代码应该可以很好地使用引用、shared_ptr和unique_ptr的组合。

确实如此,但是问题仍然存在,即使用智能指针替换原始指针也是如此。

例如,std::unique_ptr和std::shared_ptr都可以通过它们的默认构造函数构造为“空”指针:

http://en.cppreference.com/w/cpp/memory/unique_ptr/unique_ptr http://en.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr

... 这意味着在不验证它们是否为空的情况下使用它们会有崩溃的风险,这正是J. Carmack讨论的全部内容。

然后,我们有一个有趣的问题:“如何将智能指针作为函数参数传递?”

Jon对这个问题的回答是c++——将引用传递给boost::shared_ptr,下面的注释表明,即使这样,通过复制或引用传递智能指针也不像人们想的那样明确(默认情况下我倾向于使用“通过引用”,但我可能错了)。

对于指针,您需要它们指向某个对象,因此指针需要占用内存空间。

例如,接受整数指针的函数将不接受整数变量。因此,您需要首先为它创建一个指针,以便传递给函数。

作为参考,它不会占用内存。你有一个整数变量,你可以把它作为引用变量传递。就是这样。您不需要专门为它创建引用变量。