Are there benefits of passing by pointer over passing by reference in C++?
在C++中通过指针传递引用的好处是什么?
最近,我看到了许多示例,它们选择通过指针传递函数参数,而不是通过引用传递。这样做有什么好处吗?
例子:
1 | func(SPRITE *x); |
打电话来
1 | func(&mySprite); |
VS
1 | func(SPRITE &x); |
打电话来
1 | func(mySprite); |
通过指针
- 调用者必须使用地址->不透明
- 0值可用于表示
nothing 。这可用于提供可选参数。
通过引用
- 调用方只是传递对象->透明。必须用于运算符重载,因为不可能重载指针类型(指针是内置类型)。所以不能使用指针来执行
string s = &str1 + &str2; 。 - 不可能有0个值->调用的函数不必检查它们
- 对const的引用也接受临时的:
void f(const T& t); ... f(T(a, b, c)); ,指针不能这样使用,因为您不能获取临时的地址。 - 最后但并非最不重要的是,引用更容易使用->错误的可能性更小。
指针可以接收空参数,引用参数不能。如果你有机会想要传递"无对象",那么就用一个指针代替引用。
此外,通过指针传递允许您在调用站点显式地查看对象是通过值还是通过引用传递的:
1 2 3 4 5 6 | // Is mySprite passed by value or by reference? You can't tell // without looking at the definition of func() func(mySprite); // func2 passes"by pointer" - no need to look up function definition func2(&mySprite); |
Allen Holub的"足够的绳子可以射到你的脚上"列出了以下2条规则:
1 2 | 120. Reference arguments should always be `const` 121. Never use references as outputs, use pointers |
他列出了为什么将引用添加到C++中的几个原因:
- 它们是定义复制构造函数所必需的
- 它们对于运算符重载是必需的
const 引用允许您具有传递值语义,同时避免复制
他的主要观点是引用不应被用作"输出"参数,因为在调用站点上没有指示参数是引用还是值参数。所以他的规则是只使用
就我个人而言,我认为这是一个很好的经验法则,因为当一个参数是输出参数或不是输出参数时,它更清楚。然而,尽管我个人大体上同意这一点,但如果其他人将输出参数作为引用(一些开发人员非常喜欢它们),我确实允许自己被团队中其他人的意见所左右。
我喜欢"cplusplus.com:
Pass by value when the function does not want to modify the parameter and the value is easy to copy (ints, doubles, char, bool, etc... simple types. std::string, std::vector, and all other STL containers are NOT simple types.)
Pass by const pointer when the value is expensive to copy AND the function does not want to modify the value pointed to AND NULL is a valid, expected value that the function handles.
Pass by non-const pointer when the value is expensive to copy AND the function wants to modify the value pointed to AND NULL is a valid, expected value that the function handles.
Pass by const reference when the value is expensive to copy AND the function does not want to modify the value referred to AND NULL would not be a valid value if a pointer was used instead.
Pass by non-cont reference when the value is expensive to copy AND the function wants to modify the value referred to AND NULL would not be a valid value if a pointer was used instead.
When writing template functions, there isn't a clear-cut answer because there are a few tradeoffs to consider that are beyond the scope of this discussion, but suffice it to say that most template functions take their parameters by value or (const) reference, however because iterator syntax is similar to that of pointers (asterisk to"dereference"), any template function that expects iterators as arguments will also by default accept pointers as well (and not check for NULL since the NULL iterator concept has a different syntax).
http://www.cplusplus.com/articles/z6vU7k9E/
我从中得出的结论是,选择使用指针或引用参数的主要区别在于,如果NULL是一个可接受的值。就是这样。
毕竟,该值是否为输入、输出、可修改等应该在有关该函数的文档/注释中。
对上述岗位的澄清:
引用不能保证获得非空指针。(尽管我们经常这样对待他们。)
虽然非常糟糕的代码,比如说把你带到Woodshed坏代码后面,但下面的代码将编译并运行:(至少在我的编译器下)。
1 2 3 4 5 6 7 8 9 10 11 | bool test( int & a) { return (&a) == (int *) NULL; } int main() { int * i = (int *)NULL; cout << ( test(*i) ) << endl; }; |
我对引用的真正问题在于其他程序员,从此被称为白痴,他们在构造函数中分配,在析构函数中解除分配,并且未能提供复制构造函数或运算符=。
突然之间,foo(bar bar)和foo(bar&bar)之间就有了天壤之别。(将调用自动按位复制操作。析构函数中的释放被调用两次。)
值得庆幸的是,现代编译器将处理同一指针的双重释放。15年前,它们没有(在gcc/g++下,使用setenv malloc_check_0重新访问旧方法)导致在dec-unix下,在同一内存中分配给两个不同的对象。很多调试乐趣…
更实际地说:
- 引用隐藏了您正在更改存储在其他位置的数据。
- 很容易将引用与复制的对象混淆。
- 指点很明显!
不是真的。在内部,通过引用传递基本上是通过传递被引用对象的地址来执行的。所以,通过传递一个指针实际上没有任何效率的提高。
不过,通过引用传递确实有一个好处。保证您拥有正在传入的任何对象/类型的实例。如果您传入一个指针,那么您就有可能收到一个空指针。通过使用传递引用,您将向函数的调用者推送一个隐式的空检查级别。