我了解指针和引用的语法和一般语义,但是我应该如何决定什么时候在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)将调用指针版本并在运行时中断),从可维护性的角度来看,在必须存在对象的地方使用引用是有意义的,尽管失去语法的清晰性是一种遗憾。


当前回答

这不是品味的问题。以下是一些明确的规则。

如果你想在声明变量的范围内引用静态声明的变量,那么使用c++引用,这将是完全安全的。这同样适用于静态声明的智能指针。通过引用传递参数就是一个例子。

如果你想从一个比它声明的范围更宽的范围中引用任何东西,那么你应该使用一个引用计数智能指针,以确保它的完全安全。

为了语法方便,您可以使用引用引用集合的元素,但这并不安全;元素可以在任何时候被删除。

为了安全地保存对集合元素的引用,必须使用引用计数智能指针。

其他回答

正确编写的示例应该如下所示

void add_one(int& n) { n += 1; }
void add_one(int* const n)
{
  if (n)
    *n += 1;
}

这就是为什么推荐信在可能的情况下更可取 ...

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

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

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

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

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

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

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

把我的一角硬币放进去。我刚做了个测试。一个打喷嚏的人。我只是让g++使用指针而不是引用来创建同一个小程序的程序集文件。 当查看输出时,它们是完全相同的。除了符号命名。所以看性能(在一个简单的例子中)没有问题。

现在谈谈指针与引用的话题。恕我直言,我认为清晰是最重要的。一旦我读到内隐行为,我的脚趾就开始卷曲。我同意引用不能为NULL是很好的隐式行为。

解引用NULL指针不是问题所在。它将使您的应用程序崩溃,并且易于调试。一个更大的问题是未初始化的指针包含无效值。这很可能导致内存损坏,导致没有明确起源的未定义行为。

这就是我认为引用比指针安全得多的地方。我同意前面的说法,接口(应该清楚地记录,参见合同设计,Bertrand Meyer)定义了函数参数的结果。考虑到这些因素,我的偏好是 尽可能使用引用。

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

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

AddChild(Node* pNode);

以下是一些指导方针。

函数使用传递的数据而不修改它:

If the data object is small, such as a built-in data type or a small structure, pass it by value. If the data object is an array, use a pointer because that’s your only choice. Make the pointer a pointer to const. If the data object is a good-sized structure, use a const pointer or a const reference to increase program efficiency.You save the time and space needed to copy a structure or a class design. Make the pointer or reference const. If the data object is a class object, use a const reference.The semantics of class design often require using a reference, which is the main reason C++ added this feature.Thus, the standard way to pass class object arguments is by reference.

函数修改调用函数中的数据:

1.如果数据对象是内置数据类型,则使用指针。如果你是现货代码 与fixit(&x)一样,其中x是int型,很明显这个函数打算修改x。

2.如果数据对象是一个数组,则使用唯一的选择:指针。

3.如果数据对象是结构,请使用引用或指针。

4.如果数据对象是类对象,则使用引用。

当然,这些只是指导方针,可能有不同的理由 选择。例如,cin使用基本类型的引用,因此您可以使用cin >> n 而不是cin >> &n。