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


当前回答

复制自wiki-

A consequence of this is that in many implementations, operating on a variable with automatic or static lifetime through a reference, although syntactically similar to accessing it directly, can involve hidden dereference operations that are costly. References are a syntactically controversial feature of C++ because they obscure an identifier's level of indirection; that is, unlike C code where pointers usually stand out syntactically, in a large block of C++ code it may not be immediately obvious if the object being accessed is defined as a local or global variable or whether it is a reference (implicit pointer) to some other location, especially if the code mixes references and pointers. This aspect can make poorly written C++ code harder to read and debug (see Aliasing).

我完全同意这一点,这就是为什么我认为只有在你有充分理由的时候才应该使用推荐信。

其他回答

免责声明:除了引用不能为NULL或“反弹”(意味着它们不能改变它们是别名的对象)这一事实之外,它真的归结为一个品味问题,所以我不会说“这更好”。

也就是说,我不同意你在文章中最后的说法,因为我不认为代码在引用中失去了清晰度。在你的例子中,

add_one(&a);

可能会更清楚

add_one(a);

因为你知道a的值很可能会改变。另一方面,函数的签名

void add_one(int* const n);

也不太清楚n是单个整数还是数组?有时您只能访问(文档记录不佳的)头文件和签名

foo(int* const a, int b);

乍一看不容易理解。

在我看来,当不需要(重新)分配或重新绑定(在前面解释的意义上)时,引用和指针一样好。此外,如果开发人员只对数组使用指针,那么函数签名就不会那么模糊。更不用说使用引用的操作符语法可读性更强了。

我的经验法则是:

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])

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

References are cleaner and easier to use, and they do a better job of hiding information. References cannot be reassigned, however. If you need to point first to one object and then to another, you must use a pointer. References cannot be null, so if any chance exists that the object in question might be null, you must not use a reference. You must use a pointer. If you want to handle object manipulation on your own i.e if you want to allocate memory space for an object on the Heap rather on the Stack you must use Pointer

int *pInt = new int; // allocates *pInt on the Heap

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

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

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

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

要记住的要点:

指针可以为NULL,引用不能为NULL。 引用更容易使用,当我们不想改变值而只是需要在函数中引用时,const可以用作引用。 与*一起使用的指针,与&一起使用的引用。 当需要指针算术运算时使用指针。 你可以有指向void类型int a=5的指针;Void *p = &a;但不能有对void类型的引用。

指针Vs参考

void fun(int *a)
{
    cout<<a<<'\n'; // address of a = 0x7fff79f83eac
    cout<<*a<<'\n'; // value at a = 5
    cout<<a+1<<'\n'; // address of a increment by 4 bytes(int) = 0x7fff79f83eb0
    cout<<*(a+1)<<'\n'; // value here is by default = 0
}
void fun(int &a)
{
    cout<<a<<'\n'; // reference of original a passed a = 5
}
int a=5;
fun(&a);
fun(a);

判断什么时候用什么

指针:用于数组、链表、树实现和指针算术。

在函数参数和返回类型中。