C++ 何时使用引用与指针

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7058339/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 16:25:42  来源:igfitidea点击:

When to use references vs. pointers

c++pointersreference

提问by connec

I understand the syntax and general semantics of pointers versus references, but how should I decide when it is more-or-less appropriate to use references or pointers in an API?

我了解指针与引用的语法和一般语义,但我应该如何决定何时在 API 中或多或少地使用引用或指针?

Naturally some situations need one or the other (operator++needs a reference argument), but in general I'm finding I prefer to use pointers (and const pointers) as the syntax is clear that the variables are being passed destructively.

自然,有些情况需要一种或另一种(operator++需要引用参数),但总的来说,我发现我更喜欢使用指针(和 const 指针),因为语法很清楚,变量是以破坏性方式传递的。

E.g. in the following code:

例如在以下代码中:

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
}

With the pointer, it's always (more) obvious what's going on, so for APIs and the like where clarity is a big concern are pointers not more appropriate than references? Does that mean references should only be used when necessary (e.g. operator++)? Are there any performance concerns with one or the other?

使用指针,发生的事情总是(更)明显,所以对于 API 等在清晰度是一个大问题的地方,指针不比引用更合适吗?这是否意味着仅应在必要时使用引用(例如operator++)?是否有任何性能问题?

EDIT (OUTDATED):

编辑(过时):

Besides allowing NULL values and dealing with raw arrays, it seems the choice comes down to personal preference. I've accepted the answer below that references Google's C++ Style Guide, as they present the view that "References can be confusing, as they have value syntax but pointer semantics.".

除了允许 NULL 值和处理原始数组之外,似乎选择归结为个人喜好。我已经接受了下面引用Google 的 C++ 样式指南的答案,因为它们提出了“引用可能令人困惑,因为它们具有值语法但具有指针语义。”的观点。

Due to the additional work required to sanitise pointer arguments that should not be NULL (e.g. add_one(0)will call the pointer version and break during runtime), it makes sense from a maintainability perspective to use references where an object MUST be present, though it is a shame to lose the syntactic clarity.

由于清理不应为 NULL 的指针参数所需的额外工作(例如,add_one(0)将在运行时调用指针版本并中断),从可维护性的角度来看,在必须存在对象的情况下使用引用是有意义的,尽管这是一种耻辱失去句法清晰度。

采纳答案by Klaim

Use reference wherever you can, pointers wherever you must.

尽可能使用引用,必须使用指针。

Avoid pointers until you can't.

避免指针,直到你不能。

The reason is that pointers make things harder to follow/read, less safe and far more dangerous manipulations than any other constructs.

原因是指针使事情更难遵循/阅读,比任何其他结构都更不安全和更危险的操作。

So the rule of thumb is to use pointers only if there is no other choice.

所以经验法则是只有在没有其他选择时才使用指针。

For example, returning a pointer to an object is a valid option when the function can return nullptr in some cases and it is assumed it will. That said, a better option would be to use something similar to boost::optional.

例如,当函数在某些情况下可以返回 nullptr 并且假定它会返回时,返回指向对象的指针是一个有效选项。也就是说,更好的选择是使用类似于boost::optional.

Another example is to use pointers to raw memory for specific memory manipulations. That should be hidden and localized in very narrow parts of the code, to help limit the dangerous parts of the whole code base.

另一个例子是使用指向原始内存的指针来进行特定的内存操作。这应该在代码的非常狭窄的部分隐藏和本地化,以帮助限制整个代码库的危险部分。

In your example, there is no point in using a pointer as argument because:

在您的示例中,使用指针作为参数毫无意义,因为:

  1. if you provide nullptras the argument, you're going in undefined-behaviour-land;
  2. the reference attribute version doesn't allow (without easy to spot tricks) the problem with 1.
  3. the reference attribute version is simpler to understand for the user: you have to provide a valid object, not something that could be null.
  1. 如果您提供nullptr作为参数,则您将进入未定义的行为领域;
  2. 参考属性版本不允许(没有容易发现的技巧)1 的问题。
  3. 对于用户来说,引用属性版本更容易理解:您必须提供一个有效的对象,而不是可能为 null 的对象。

If the behaviour of the function would have to work with or without a given object, then using a pointer as attribute suggests that you can pass nullptras the argument and it is fine for the function. That's kind of a contract between the user and the implementation.

如果函数的行为必须在有或没有给定对象的情况下工作,那么使用指针作为属性表明您可以nullptr作为参数传递,这对函数来说很好。这是用户和实现之间的一种契约。

回答by Andrea Bergia

The performances are exactly the same, as references are implemented internally as pointers. Thus you do not need to worry about that.

性能完全相同,因为引用在内部实现为指针。因此,您无需担心。

There is no generally accepted convention regarding when to use references and pointers. In a few cases you have to return or accept references (copy constructor, for instance), but other than that you are free to do as you wish. A rather common convention I've encountered is to use references when the parameter must refer an existing object and pointers when a NULL value is ok.

关于何时使用引用和指针没有普遍接受的约定。在少数情况下,您必须返回或接受引用(例如复制构造函数),但除此之外,您可以随心所欲。我遇到的一个相当普遍的约定是在参数必须引用现有对象时使用引用,而在 NULL 值正常时使用指针。

Some coding convention (like Google's) prescribe that one should always use pointers, or const references, because references have a bit of unclear-syntax: they have reference behaviour but value syntax.

一些编码约定(如Google 的)规定应该始终使用指针或常量引用,因为引用的语法有点不清楚:它们具有引用行为但具有值语法。

回答by Mahesh

From C++ FAQ Lite-

来自C++ FAQ Lite-

Use references when you can, and pointers when you have to.

References are usually preferred over pointers whenever you don't need "reseating". This usually means that references are most useful in a class's public interface. References typically appear on the skin of an object, and pointers on the inside.

The exception to the above is where a function's parameter or return value needs a "sentinel" reference — a reference that does not refer to an object. This is usually best done by returning/taking a pointer, and giving the NULL pointer this special significance (references must always alias objects, not a dereferenced NULL pointer).

Note: Old line C programmers sometimes don't like references since they provide reference semantics that isn't explicit in the caller's code. After some C++ experience, however, one quickly realizes this is a form of information hiding, which is an asset rather than a liability. E.g., programmers should write code in the language of the problem rather than the language of the machine.

可以时使用引用,必要时使用指针。

每当您不需要“重置”时,引用通常比指针更受欢迎。这通常意味着引用在类的公共接口中最有用。引用通常出现在对象的外观上,而指针出现在内部。

上面的例外是函数的参数或返回值需要“哨兵”引用——一个不引用对象的引用。这通常最好通过返回/获取指针并赋予 NULL 指针这种特殊意义来完成(引用必须始终是对象的别名,而不是取消引用的 NULL 指针)。

注意:老 C 程序员有时不喜欢引用,因为它们提供了在调用者代码中不明确的引用语义。然而,在一些 C++ 经验之后,人们很快就会意识到这是一种信息隐藏形式,它是一种资产而不是一种负债。例如,程序员应该用问题的语言而不是机器的语言编写代码。

回答by Calmarius

My rule of thumb is:

我的经验法则是:

  • 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 constif 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])
  • 将指针用于传出或输入/输出参数。所以可以看出这个值是要改变的。(你必须使用&
  • 如果 NULL 参数是可接受的值,则使用指针。(确保它const是传入参数)
  • 如果传入参数不能为 NULL 并且不是原始类型 ( const T&) ,则使用传入参数的引用。
  • 返回新创建的对象时使用指针或智能指针。
  • 使用指针或智能指针作为结构或类成员而不是引用。
  • 使用别名的引用(例如。int &current = someArray[i]

Regardless which one you use, don't forget to document your functions and the meaning of their parameters if they are not obvious.

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

回答by bartgol

Disclaimer: other than the fact that references cannot be NULL nor "rebound" (meaning thay can't change the object they're the alias of), it really comes down to a matter of taste, so I'm not going to say "this is better".

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

That said, I disagree with your last statement in the post, in that I don't think the code loses clarity with references. In your example,

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

add_one(&a);

might be clearer than

可能比

add_one(a);

since you know that most likely the value of a is going to change. On the other hand though, the signature of the function

因为您知道 a 的值很可能会发生变化。但另一方面,函数的签名

void add_one(int* const n);

is somewhat not clear either: is n going to be a single integer or an array? Sometimes you only have access to (poorly documentated) headers, and signatures like

也有点不清楚:n 是单个整数还是数组?有时您只能访问(记录不充分的)标题和签名,例如

foo(int* const a, int b);

are not easy to interpret at first sight.

乍一看并不容易理解。

Imho, references are as good as pointers when no (re)allocation nor rebinding (in the sense explained before) is needed. Moreover, if a developer only uses pointers for arrays, functions signatures are somewhat less ambiguous. Not to mention the fact that operators syntax is way more readable with references.

恕我直言,当不需要(重新)分配或重新绑定(在前面解释的意义上)时,引用与指针一样好。此外,如果开发人员只使用数组的指针,函数签名就不那么模糊了。更不用说运算符语法在引用时更具可读性这一事实。

回答by paercebal

Like others already answered: Always use references, unless the variable being NULL/nullptris reallya valid state.

与其他人一样已经回答了:始终使用引用,除非该变量的存在NULL/nullptr真正有效的状态。

John Carmack's viewpoint on the subject is similar:

约翰卡马克对这个问题的观点是相似的:

NULL pointers are the biggest problem in C/C++, at least in our code. The dual use of a single value as both a flag and an address causes an incredible number of fatal issues. C++ references should be favored over pointers whenever possible; while a reference is “really” just a pointer, it has the implicit contract of being not-NULL. Perform NULL checks when pointers are turned into references, then you can ignore the issue thereafter.

NULL 指针是 C/C++ 中最大的问题,至少在我们的代码中是这样。将单个值同时用作标志和地址会导致数量惊人的致命问题。应尽可能使用 C++ 引用而不是指针;虽然引用“实际上”只是一个指针,但它具有非 NULL 的隐式约定。当指针变为引用时执行 NULL 检查,然后您可以忽略此问题。

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

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

Edit 2012-03-13

编辑 2012-03-13

User Bret Kuhnsrightly remarks:

用户Bret Kuhns正确评论:

The C++11 standard has been finalized. I think it's time in this thread to mention that most code should do perfectly fine with a combination of references, shared_ptr, and unique_ptr.

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

True enough, but the question still remains, even when replacing raw pointers with smart pointers.

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

For example, both std::unique_ptrand std::shared_ptrcan be constructed as "empty" pointers through their default constructor:

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

... meaning that using them without verifying they are not empty risks a crash, which is exactly what J. Carmack's discussion is all about.

...意味着在不验证它们不是空的情况下使用它们可能会导致崩溃,这正是 J. Carmack 讨论的全部内容。

And then, we have the amusing problem of "how do we pass a smart pointer as a function parameter?"

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

Jon's answerfor the question C++ - passing references to boost::shared_ptr, and the following comments show that even then, passing a smart pointer by copy or by reference is not as clear cut as one would like (I favor myself the "by-reference" by default, but I could be wrong).

JonC++问题的回答- 传递对 boost::shared_ptr 的引用,以及以下评论表明,即便如此,通过复制或通过引用传递智能指针并不像人们希望的那样清晰(我喜欢自己“ by-reference”默认情况下,但我可能是错的)。

回答by John Morrison

It is not a matter of taste. Here are some definitive rules.

这不是品味问题。这里有一些明确的规则。

If you want to refer to a statically declared variable within the scope in which it was declared then use a C++ reference, and it will be perfectly safe. The same applies to a statically declared smart pointer. Passing parameters by reference is an example of this usage.

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

If you want to refer to anything from a scope that is wider than the scope in which it is declared then you should use a reference counted smart pointer for it to be perfectly safe.

如果你想从比它声明的范围更宽的范围内引用任何东西,那么你应该使用引用计数的智能指针,因为它是完全安全的。

You can refer to an element of a collection with a reference for syntactic convenience, but it is not safe; the element can be deleted at anytime.

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

To safely hold a reference to an element of a collection you must use a reference counted smart pointer.

要安全地持有对集合元素的引用,您必须使用引用计数智能指针。

回答by David Schwartz

Any performance difference would be so small that it wouldn't justify using the approach that's less clear.

任何性能差异都非常小,以至于无法证明使用不太明确的方法是合理的。

First, one case that wasn't mentioned where references are generally superior is constreferences. For non-simple types, passing a const referenceavoids creating a temporary and doesn't cause the confusion you're concerned about (because the value isn't modified). Here, forcing a person to pass a pointer causes the very confusion you're worried about, as seeing the address taken and passed to a function might make you think the value changed.

首先,没有提到引用通常更好的一种情况是const引用。对于非简单类型,传递 aconst reference可避免创建临时类型,并且不会引起您所担心的混淆(因为值未修改)。在这里,强迫一个人传递一个指针会导致你所担心的非常混乱,因为看到地址被获取并传递给一个函数可能会让你认为值改变了。

In any event, I basically agree with you. I don't like functions taking references to modify their value when it's not very obvious that this is what the function is doing. I too prefer to use pointers in that case.

无论如何,我基本上同意你的看法。当函数正在执行的操作不是很明显时,我不喜欢函数通过引用来修改它们的值。在这种情况下,我也更喜欢使用指针。

When you need to return a value in a complex type, I tend to prefer references. For example:

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

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

Here, the function name makes it clear that you're getting information back in an array. So there's no confusion.

在这里,函数名称清楚地表明您正在从数组中获取信息。所以没有混淆。

The main advantages of references are that they always contain a valid value, are cleaner than pointers, and support polymorphism without needing any extra syntax. If none of these advantages apply, there is no reason to prefer a reference over a pointer.

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

回答by user606723

Copied from 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).

这样做的结果是,在许多实现中,通过引用对具有自动或静态生命周期的变量进行操作,尽管在语法上与直接访问它类似,但可能涉及代价高昂的隐藏取消引用操作。引用是 C++ 的一个在语法上有争议的特性,因为它们掩盖了标识符的间接级别;也就是说,与指针通常在语法上突出的 C 代码不同,在一大块 C++ 代码中,如果被访问的对象被定义为局部或全局变量,或者它是否是对其他一些位置,尤其是在代码混合引用和指针的情况下。这方面会使编写得不好的 C++ 代码更难阅读和调试(请参阅别名)。

I agree 100% with this, and this is why I believe that you should only use a reference when you a have very good reason for doing so.

我 100% 同意这一点,这就是为什么我认为您应该只在有充分理由时才使用参考资料。

回答by shaurya uppal

Points to keep in mind:

要记住的要点:

  1. Pointers can be NULL, references cannot be NULL.

  2. References are easier to use, constcan be used for a reference when we don't want to change value and just need a reference in a function.

  3. Pointer used with a *while references used with a &.

  4. Use pointers when pointer arithmetic operation are required.

  5. You can have pointers to a void type int a=5; void *p = &a;but cannot have a reference to a void type.

  1. 指针可以NULL,引用不能NULL

  2. 引用更容易使用,const当我们不想改变值而只需要函数中的引用时,可以用作引用。

  3. *while 一起使用的指针与 a一起使用的引用&

  4. 当需要指针算术运算时使用指针。

  5. 您可以拥有指向 void 类型的指针,int a=5; void *p = &a;但不能拥有指向 void 类型的引用。

Pointer Vs Reference

指针与参考

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

Verdict when to use what

判断何时使用什么

Pointer: For array, linklist, tree implementations and pointer arithmetic.

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

Reference: In function parameters and return types.

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