在C ++中通过引用传递指针是否有好处?

在C ++中通过引用传递指针有什么好处?

最近,我已经看到了许多select通过指针传递函数参数而不是通过引用传递的例子。 这样做有好处吗?

例:

func(SPRITE *x); 

随叫随到

 func(&mySprite); 

 func(SPRITE &x); 

随叫随到

 func(mySprite); 

一个指针可以接收一个NULL参数,一个参考参数不能。 如果有可能想要传递“no object”,那么使用指针而不是引用。

而且,通过指针传递可以让你在调用的地方显式地看到对象是按值还是按引用传递的:

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

指针传递

  • 来电者必须采取地址 – >不透明
  • 可以提供0值来表示nothing 。 这可以用来提供可选的参数。

通过参考传递

  • 调用者只是传递对象 – >透明。 必须用于操作符重载,因为指针types的重载是不可能的(指针是内置types)。 所以你不能做string s = &str1 + &str2; 使用指针。
  • 没有可能的值 – >被调用函数不必检查它们
  • 引用const也接受临时对象: void f(const T& t); ... f(T(a, b, c)); void f(const T& t); ... f(T(a, b, c)); ,指针不能这样使用,因为你不能获取临时地址。
  • 最后但并非最不重要的是,引用更容易使用 – >错误的机会更less。

艾伦·霍勒布(Allen Holub)的“足够的绳索在脚下射击”列出了以下两条规则:

 120. Reference arguments should always be `const` 121. Never use references as outputs, use pointers 

他列举了为什么引用被添加到C ++的几个原因:

  • 他们有必要定义拷贝构造函数
  • 他们是运营商超负荷所必需的
  • const引用允许您在传递值的同时避免复制

他的主要观点是引用不应该用作“输出”参数,因为在调用地点没有指示参数是引用还是值参数。 所以他的规则是只使用const引用作为参数。

就个人而言,我认为这是一个很好的经验法则,因为当参数是一个输出参数或者不是一个输出参数的时候,它就会更加清晰。 然而,虽然我个人同意这个观点,但是如果他们争论输出参数作为参考(一些开发者喜欢他们),我确实会让我自己受到团队中其他人的意见的影响。

我喜欢“cplusplus.com”一文的推理:

  1. 当函数不想修改参数时,通过值传递,值很容易复制(ints,doubles,char,bool等等…简单types。std :: string,std :: vector和其他所有STL容器不是简单的types。)

  2. 当值复制的代价很大时,通过const指针传递并且函数不希望修改指向的值AND NULL是函数处理的有效期望值。

  3. 当值非常昂贵时,通过非const指针传递并且函数想要修改指向的值AND NULL是函数处理的有效期望值。

  4. 当通过const引用传递值时,复制的代价太大并且该函数不希望修改引用的值,如果使用指针而不是有效值,则NULL将不是有效的值。

  5. 当值复制的代价很高时,通过非循环引用传递并且函数要修改引用的值,如果使用指针而不是有效值。

  6. 在编写模板函数的时候,没有一个明确的答案,因为有几个折衷考虑超出了这个讨论的范围,但足以说大多数模板函数都是通过值或(const)引用,但是因为迭代器的语法与指针的类似(星号为“dereference”),任何需要迭代器作为参数的模板函数也会默认接受指针(因为NULL迭代器概念有不同的语法)。

http://www.cplusplus.com/articles/z6vU7k9E/

我从中得出的结论是select使用指针或引用参数的主要区别在于,如果NULL是可接受的值。 而已。

毕竟值的input,输出,可修改等都应该在有关函数的文档/注释中。

对前面的post的说明:


引用不是获取非空指针的保证。 (虽然我们经常这样对待他们。)

虽然可怕的代码不好,就像把你排除在拙劣的代码之后,下面的代码会编译和运行:(至less在我的编译器下面)

 bool test( int & a) { return (&a) == (int *) NULL; } int main() { int * i = (int *)NULL; cout << ( test(*i) ) << endl; }; 

真正的问题,我有参考与其他程序员,从此以后称为IDIOTS ,谁在构造函数中分配,释放析构函数, 并提供复制构造函数或运算符=()。

突然之间, 富(BAR酒吧)foo(BAR 酒吧)之间有一个世界的区别。 (调用自动按位复制操作,在析构函数中取消分配被调用两次。

值得庆幸的是,现代编译器会拿起同一个指针的这个双重释放。 15年前,他们没有。 (在gcc / g ++下,使用setenv MALLOC_CHECK_ 0重新访问旧的方法。)在DEC UNIX下,在同一内存中产生两个不同的对象。 那里有很多debugging的乐趣…


更实际:

  • 引用隐藏你正在改变存储在其他地方的数据。
  • 将引用与复制对象混淆很容易。
  • 指针显而易见!

不是真的。 在内部,传递引用是通过传递引用对象的地址来实现的。 所以,通过指针确实没有任何效率提升。

通过引用传递确实有一个好处,但是。 你保证有一个被传入的对象/types的实例。如果你传入一个指针,那么你冒着接收一个NULL指针的风险。 通过使用pass-by-reference,你正在向你的函数的调用者推送一个隐式的NULL-检查一个级别。