Pointer vs. Reference
在给函数提供原始变量时,最好的做法是:
1 2 3 4 5 6 | unsigned long x = 4; void func1(unsigned long& val) { val = 5; } func1(x); |
或:
1 2 3 4 | void func2(unsigned long* val) { *val = 5; } func2(&x); |
值班驾驶员:有没有理由选择一个而不是另一个?
我的经验法则是:
如果要使用指针进行指针算术(例如,增加指针地址以逐步通过数组),或者如果必须传递空指针,请使用指针。
否则使用引用。
我真的认为您将受益于建立以下函数调用编码准则:
和其他地方一样,总是正确的。
- 注:这意味着,除其他外,只有out值(见第3项)和value传递的值(见第4项)可能缺少
const 说明符。
仅当值0/null是当前上下文中的有效输入时,才按指针传递值。
理由1:作为一个调用者,你会看到你传递的信息必须处于可用状态。
理由2:正如所说,你知道任何东西都处于可用状态。因此,不需要对该值进行空检查或错误处理。
理由3:基本原理1和2将由编译器强制执行。如果可以的话,总是在编译时捕获错误。
如果函数参数是out值,则通过引用传递它。
- 理由:我们不想破坏第2项……
只有当值是pod(普通的旧数据结构)或足够小(内存方面)或以其他方式足够便宜(时间方面)复制时,才选择"pass-by-value"而不是"pass-by-const-reference"。
- 理由:避免不必要的复制品。
- 注:足够小和足够便宜不是绝对可测量的。
这最终是主观的。到目前为止,讨论是有用的,但我认为没有正确或决定性的答案。很大程度上取决于风格指南和您当时的需求。
虽然指针具有一些不同的功能(无论是否可以为空),但输出参数的最大实际差异是纯语法。谷歌的C++风格指南(http://谷歌,Github.Io/StultGueld/CppGueld.html引用引用参数),例如,只为输出参数指定指针,只允许引用const。推理是可读性的一种:具有值语法的东西不应该具有指针语义意义。我不是说这必然是对的或错的,但我认为这里的重点是,这是一个风格问题,而不是正确性问题。
如果要修改变量的值,应该传递一个指针。尽管从技术上讲传递引用或指针是相同的,但是在用例中传递指针更易读,因为它"宣传"了值将被函数更改的事实。
如果您有一个参数,可能需要在其中指示缺少值,那么通常的做法是将该参数设置为指针值并传入空值。
在大多数情况下(从安全的角度来看),更好的解决方案是使用boost::可选。这允许您通过引用和作为返回值传入可选值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | // 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); } |
指针
- 指针是保存内存地址的变量。
- 指针声明由基类型、*、变量名组成。
- 指针可以指向生命周期中任意数量的变量
当前未指向有效内存位置的指针的值为空(零)。
1
2
3BaseType* ptrBaseType;
BaseType objBaseType;
ptrBaseType = &objBaseType;&;是返回其操作数的内存地址的一元运算符。
取消引用运算符(*)用于访问指针指向的变量中存储的值。
1
2
3int nVar = 7;
int* ptrVar = &nVar;
int nVar2 = *ptrVar;
参考文献
引用(&;)类似于现有变量的别名。
引用(&;)就像一个自动取消引用的常量指针。
它通常用于函数参数列表和函数返回值。
创建引用时必须对其进行初始化。
一旦一个引用初始化为一个对象,它就不能更改为引用另一个对象。
不能有空引用。
const引用可以引用const int。它是用一个值为const的临时变量完成的。
1
2
3int 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
可以时使用引用,必要时使用指针。从C++ FAQ:"我应该什么时候使用引用,什么时候我应该使用指针?"
考虑C的out关键字。编译器要求方法的调用者将out关键字应用于任何out参数,即使它已经知道它们是否是。这是为了增强可读性。尽管使用现代的IDES,我倾向于认为这是语法(或语义)突出显示的工作。
引用是一个隐式指针。基本上,您可以更改引用指向的值,但不能更改引用指向其他对象。所以我的2分是,如果你只想改变一个参数的值,作为一个引用传递它,但是如果你需要改变这个参数来指向一个不同的对象,用一个指针传递它。
指针:
- 可以指定
nullptr (或NULL )。 - 在调用站点,如果您的类型不是指针本身,则必须使用
& ,明确表示您正在修改对象。 - 指针可以反弹。
参考文献:
- 不能为空。
- 一旦绑定,就无法更改。
- 呼叫者不需要明确使用
& 。有时会考虑不好,因为您必须转到函数的实现来查看您的参数已修改。
传递常量引用,除非您希望更改/保留要传递的内容。
在大多数情况下,这将是最有效的方法。
确保在不希望更改的每个参数上使用const,因为这样不仅可以防止您在函数中做一些愚蠢的事情,还可以向其他用户很好地指示函数对传入值的作用。这包括当您只想更改指向的内容时创建一个指针常量…
引用类似于指针,只是不需要使用前缀?访问引用引用的值。此外,在初始化后不能使引用引用引用其他对象。
引用对于指定函数参数特别有用。
有关更多信息,请参见"Bjarne Stroustrup"(2014)页11-12的"C++之旅"