简体   繁体   English

指针与参考

[英]Pointer vs. Reference

What would be better practice when giving a function the original variable to work with: 在给函数提供原始变量时,最好的做法是:

unsigned long x = 4;

void func1(unsigned long& val) {
     val = 5;            
}
func1(x);

or: 要么:

void func2(unsigned long* val) {
     *val = 5;
}
func2(&x);

IOW: Is there any reason to pick one over another? IOW:有没有理由选择一个而不是另一个?

My rule of thumb is: 我的经验法则是:

Use pointers if you want to do pointer arithmetic with them (eg incrementing the pointer address to step through an array) or if you ever have to pass a NULL-pointer. 如果你想用它们做指针运算(例如递增指针地址以逐步遍历数组)或者你必须传递一个NULL指针,请使用指针。

Use references otherwise. 否则使用参考。

I really think you will benefit from establishing the following function calling coding guidelines: 我真的认为你将从建立以下函数调用编码指南中受益:

  1. As in all other places, always be const -correct. 正如其他所有地方,永远是const -correct。

    • Note: This means, among other things, that only out-values (see item 3) and values passed by value (see item 4) can lack the const specifier. 注意:除其他外,这意味着只有out-values(参见第3项)和value传递的值(参见第4项)可能缺少const说明符。
  2. Only pass a value by pointer if the value 0/NULL is a valid input in the current context. 如果值0 / NULL是当前上下文中的有效输入,则仅通过指针传递值。

    • Rationale 1: As a caller , you see that whatever you pass in must be in a usable state. 理由1:作为调用者 ,您会看到无论您传入的是什么,都必须处于可用状态。

    • Rationale 2: As called , you know that whatever comes in is in a usable state. 理由2:由于 ,你知道,无论发生什么事在处于可用状态。 Hence, no NULL-check or error handling needs to be done for that value. 因此,不需要对该值进行NULL检查或错误处理。

    • Rationale 3: Rationales 1 and 2 will be compiler enforced . 基本原理3:基础知识1和2将被编译器强制执行 Always catch errors at compile time if you can. 如果可以的话,总是在编译时捕获错误。

  3. If a function argument is an out-value, then pass it by reference. 如果函数参数是out-value,则通过引用传递它。

    • Rationale: We don't want to break item 2... 理由:我们不想打破第2项......
  4. Choose "pass by value" over "pass by const reference" only if the value is a POD ( Plain old Datastructure ) or small enough (memory-wise) or in other ways cheap enough (time-wise) to copy. 只有当值是POD( 普通旧数据结构 )或足够小(内存方式)或以其他方式足够便宜(按时间)复制时,选择“按值传递”而不是“传递const引用”。

    • Rationale: Avoid unnecessary copies. 理由:避免不必要的副本。
    • Note: small enough and cheap enough are not absolute measurables. 注意: 小到足够 便宜并不是绝对可衡量的。

This ultimately ends up being subjective. 这最终成为主观的。 The discussion thus far is useful, but I don't think there is a correct or decisive answer to this. 到目前为止的讨论很有用,但我认为没有正确或果断的答案。 A lot will depend on style guidelines and your needs at the time. 很多将取决于风格指南和您当时的需求。

While there are some different capabilities (whether or not something can be NULL) with a pointer, the largest practical difference for an output parameter is purely syntax. 虽然使用指针有一些不同的功能(无论是否可以为NULL),但输出参数的最大实际差异纯粹是语法。 Google's C++ Style Guide ( https://google.github.io/styleguide/cppguide.html#Reference_Arguments ), for example, mandates only pointers for output parameters, and allows only references that are const. 例如,谷歌的C ++风格指南( https://google.github.io/styleguide/cppguide.html#Reference_Arguments )只强制指针输出参数,并且只允许引用为const。 The reasoning is one of readability: something with value syntax should not have pointer semantic meaning. 推理是可读性:具有值语法的东西不应该具有指针语义。 I'm not suggesting that this is necessarily right or wrong, but I think the point here is that it's a matter of style, not of correctness. 我并不是说这必然是对或错,但我认为这里的重点是风格,而不是正确性。

You should pass a pointer if you are going to modify the value of the variable. 如果要修改变量的值,则应传递指针。 Even though technically passing a reference or a pointer are the same, passing a pointer in your use case is more readable as it "advertises" the fact that the value will be changed by the function. 即使技术上传递引用或指针是相同的,在您的用例中传递指针更具可读性,因为它“通告”该值将由函数更改的事实。

If you have a parameter where you may need to indicate the absence of a value, it's common practice to make the parameter a pointer value and pass in NULL. 如果您有一个参数,您可能需要指示缺少值,通常的做法是使参数成为指针值并传入NULL。

A better solution in most cases (from a safety perspective) is to use boost::optional . 在大多数情况下(从安全角度来看)更好的解决方案是使用boost :: optional This allows you to pass in optional values by reference and also as a return value. 这允许您通过引用传递可选值,也可以作为返回值。

// Sample method using optional as input parameter
void PrintOptional(const boost::optional<std::string>& optional_str)
{
    if (optional_str)
    {
       cout << *optional_str << std::endl;
    }
    else
    {
       cout << "(no string)" << std::endl;
    }
}

// Sample method using optional as return value
boost::optional<int> ReturnOptional(bool return_nothing)
{
    if (return_nothing)
    {
       return boost::optional<int>();
    }

    return boost::optional<int>(42);
}

Pointers 指针

  • A pointer is a variable that holds a memory address. 指针是保存内存地址的变量。
  • A pointer declaration consists of a base type, an *, and the variable name. 指针声明由基类型,*和变量名组成。
  • A pointer can point to any number of variables in lifetime 指针可以指向生命周期中的任意数量的变量
  • A pointer that does not currently point to a valid memory location is given the value null (Which is zero) 当前未指向有效内存位置的指针的值为null(为零)

     BaseType* ptrBaseType; BaseType objBaseType; ptrBaseType = &objBaseType; 
  • The & is a unary operator that returns the memory address of its operand. &是一个一元运算符,返回其操作数的内存地址。

  • Dereferencing operator (*) is used to access the value stored in the variable which pointer points to. 解除引用运算符(*)用于访问存储在指针指向的变量中的值。

      int nVar = 7; int* ptrVar = &nVar; int nVar2 = *ptrVar; 

Reference 参考

  • A reference (&) is like an alias to an existing variable. 引用(&)类似于现有变量的别名。

  • A reference (&) is like a constant pointer that is automatically dereferenced. 引用(&)就像一个自动解除引用的常量指针。

  • It is usually used for function argument lists and function return values. 它通常用于函数参数列表和函数返回值。

  • A reference must be initialized when it is created. 必须在创建引用时初始化引用。

  • Once a reference is initialized to an object, it cannot be changed to refer to another object. 将引用初始化为对象后,无法将其更改为引用另一个对象。

  • You cannot have NULL references. 您不能有NULL引用。

  • A const reference can refer to a const int. const引用可以引用const int。 It is done with a temporary variable with value of the const 它由一个带有const值的临时变量完成

     int i = 3; //integer declaration int * pi = &i; //pi points to the integer i int& ri = i; //ri is refers to integer i – creation of reference and initialization 

在此输入图像描述

在此输入图像描述

Use a reference when you can, use a pointer when you have to. 尽可能使用引用,必要时使用指针。 From C++ FAQ: "When should I use references, and when should I use pointers?" C ++ FAQ:“我应该何时使用引用,何时应该使用指针?”

A reference is an implicit pointer. 引用是隐式指针。 Basically you can change the value the reference points to but you can't change the reference to point to something else. 基本上,您可以更改引用指向的值,但不能将引用更改为指向其他内容。 So my 2 cents is that if you only want to change the value of a parameter pass it as a reference but if you need to change the parameter to point to a different object pass it using a pointer. 所以我的2美分是,如果您只想更改参数的值,则将其作为参考传递,但如果您需要将参数更改为指向其他对象,请使用指针传递它。

Consider C#'s out keyword. 考虑一下C#的out关键字。 The compiler requires the caller of a method to apply the out keyword to any out args, even though it knows already if they are. 编译器要求方法的调用者将out关键字应用于任何out args,即使它已经知道它们是否存在。 This is intended to enhance readability. 这旨在增强可读性。 Although with modern IDEs I'm inclined to think that this is a job for syntax (or semantic) highlighting. 虽然使用现代IDE,我倾向于认为这是语法(或语义)突出显示的工作。

Pass by const reference unless there is a reason you wish to change/keep the contents you are passing in. 除非您有理由更改/保留您传入的内容,否则请通过const引用。

This will be the most efficient method in most cases. 在大多数情况下,这将是最有效的方法。

Make sure you use const on each parameter you do not wish to change, as this not only protects you from doing something stupid in the function, it gives a good indication to other users what the function does to the passed in values. 确保在每个不希望更改的参数上使用const,因为这不仅可以保护您不会在函数中做一些愚蠢的事情,而且可以很好地向其他用户指示函数对传入的值的作用。 This includes making a pointer const when you only want to change whats pointed to... 这包括当你只想改变指向的时候制作指针const ...

Pointers: 指针:

  • Can be assigned nullptr (or NULL ). 可以分配nullptr (或NULL )。
  • At the call site, you must use & if your type is not a pointer itself, making explicitly you are modifying your object. 在调用站点,如果您的类型不是指针本身,则必须使用& ,明确表示您正在修改对象。
  • Pointers can be rebound. 指针可以反弹。

References: 参考文献:

  • Cannot be null. 不能为空。
  • Once bound, cannot change. 一旦绑定,就无法改变。
  • Callers don't need to explicitly use & . 呼叫者不需要明确使用& This is considered sometimes bad because you must go to the implementation of the function to see if your parameter is modified. 这有时被认为是错误的,因为您必须转到函数的实现以查看您的参数是否被修改。

A reference is similar to a pointer, except that you don't need to use a prefix ∗ to access the value referred to by the reference. 引用类似于指针,除了您不需要使用前缀*来访问引用引用的值。 Also, a reference cannot be made to refer to a different object after its initialization. 此外,不能在初始化之后引用不同的对象。

References are particularly useful for specifying function arguments. 引用对于指定函数参数特别有用。

for more information see "A Tour of C++" by "Bjarne Stroustrup" (2014) Pages 11-12 有关更多信息,请参阅“Bjarne Stroustrup”(2014)第11-12页的“C ++之旅”

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM