在C++中通过引用传递指针有什么好处?
最近,我看到一些例子选择通过指针传递函数参数而不是通过引用传递.这样做有好处吗?
例:
func(SPRITE *x);
随叫随到
func(&mySprite);
与
func(SPRITE &x);
随叫随到
func(mySprite);
Johannes Sch.. 236
来电者必须拿地址 - >不透明
可以提供0值来表示nothing
.这可用于提供可选参数.
调用者只是传递对象 - >透明.必须用于运算符重载,因为指针类型的重载是不可能的(指针是内置类型).所以你不能 string s = &str1 + &str2;
使用指针.
可能没有0值 - >被调用的函数不必检查它们
对const的引用也接受临时性:void f(const T& t); ... f(T(a, b, c));
指针不能像那样使用,因为你不能使用临时的地址.
最后但同样重要的是,引用更容易使用 - >错误的机会更少.
我不同意"减少错误的机会".当检查呼叫站点并且读者看到"foo(&s)"时,立即清楚可以修改s.当您阅读"foo(s)"时,如果可以修改s,则一点都不清楚.这是错误的主要来源.也许某类错误的可能性较小,但总的来说,通过引用传递是一个巨大的错误来源. (42认同)
"透明"是什么意思? (23认同)
通过指针传递也会提出"是否已转让所有权?" 题.参考不是这种情况. (7认同)
@ MichaelJ.Davenport - 在你的解释中,你建议使用"透明"来表示"显然调用者正在传递指针,但调用者传递引用并不明显".在约翰内斯的帖子中,他说"通过指针传递 - 来电者必须采取地址 - >不透明"和"通过参考传递 - 来电者只是通过对象 - >透明" - 这几乎与你说的相反.我认为Gbert90的问题"透明"是什么意思仍然有效. (3认同)
@ Gbert90,如果你在调用网站上看到foo(&a),你知道foo()采用指针类型.如果你看到foo(a),你不知道它是否需要参考. (2认同)
Adam Rosenfi.. 212
一个指针可以接收一个NULL参数,一个参数参数不能.如果您有可能想要传递"无对象",则使用指针而不是引用.
此外,通过指针传递允许您在调用站点显式地查看对象是通过值还是通过引用传递:
// 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);
答案不完整.使用指针不会授权临时/提升对象的使用,也不会使用尖头对象作为类似堆栈的对象.并且当大多数时候应该禁止NULL值时,它会建议参数可以为NULL.阅读litb的答案以获得完整的答案. (17认同)
Michael Burr.. 62
艾伦·霍鲁布的"足够的足球射门"列出了以下两条规则:
120. Reference arguments should always be `const` 121. Never use references as outputs, use pointers
他列举了为什么将引用添加到C++的几个原因:
它们是定义复制构造函数所必需的
它们是操作员超载所必需的
const
引用允许您在避免复制的同时具有按值传递的语义
他的主要观点是参考不应该用作"输出"参数,因为在呼叫站点没有指示参数是参考还是值参数.所以他的规则是只使用const
引用作为参数.
就个人而言,我认为这是一个很好的经验法则,因为当参数是输出参数时它会更清楚.然而,虽然我个人同意这一点,但我确实允许自己受到团队中其他人的意见的影响,如果他们争论输出参数作为参考(一些开发人员非常喜欢它们).
来电者必须拿地址 - >不透明
可以提供0值来表示nothing
.这可用于提供可选参数.
调用者只是传递对象 - >透明.必须用于运算符重载,因为指针类型的重载是不可能的(指针是内置类型).所以你不能 string s = &str1 + &str2;
使用指针.
可能没有0值 - >被调用的函数不必检查它们
对const的引用也接受临时性:void f(const T& t); ... f(T(a, b, c));
指针不能像那样使用,因为你不能使用临时的地址.
最后但同样重要的是,引用更容易使用 - >错误的机会更少.
一个指针可以接收一个NULL参数,一个参数参数不能.如果您有可能想要传递"无对象",则使用指针而不是引用.
此外,通过指针传递允许您在调用站点显式地查看对象是通过值还是通过引用传递:
// 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);
艾伦·霍鲁布的"足够的足球射门"列出了以下两条规则:
120. Reference arguments should always be `const` 121. Never use references as outputs, use pointers
他列举了为什么将引用添加到C++的几个原因:
它们是定义复制构造函数所必需的
它们是操作员超载所必需的
const
引用允许您在避免复制的同时具有按值传递的语义
他的主要观点是参考不应该用作"输出"参数,因为在呼叫站点没有指示参数是参考还是值参数.所以他的规则是只使用const
引用作为参数.
就个人而言,我认为这是一个很好的经验法则,因为当参数是输出参数时它会更清楚.然而,虽然我个人同意这一点,但我确实允许自己受到团队中其他人的意见的影响,如果他们争论输出参数作为参考(一些开发人员非常喜欢它们).
我喜欢"cplusplus.com"中一篇文章的推理.
当函数不想修改参数并且值很容易复制时传递值(int,double,char,bool等...简单类型.std :: string,std :: vector和所有其他STL容器不是简单的类型.)
当复制值很昂贵时传递const指针并且函数不想修改指向的值AND NULL是函数处理的有效预期值.
当复制值很昂贵时,通过非const指针传递并且函数想要修改指向的值AND NULL是函数处理的有效预期值.
当复制值很昂贵时,通过const引用,并且函数不想修改引用的值.如果使用指针,NULL将不是有效值.
当复制值很昂贵时,通过非连续引用,并且函数想要修改引用的值.如果使用指针,NULL将不是有效值.
在编写模板函数时,没有明确的答案,因为需要考虑的一些权衡超出了本讨论的范围,但足以说大多数模板函数通过值或(const)引用获取其参数但是因为迭代器语法类似于指针(星号到"取消引用"),任何期望迭代器作为参数的模板函数也会默认接受指针(并且不检查NULL,因为NULL迭代器概念具有不同的语法).
http://www.cplusplus.com/articles/z6vU7k9E/
我从中得到的是,选择使用指针或引用参数之间的主要区别在于NULL是否是可接受的值.而已.
毕竟,值是输入,输出,可修改等应该在关于函数的文档/注释中.
澄清前面的帖子:
引用不是获取非空指针的保证.(虽然我们经常这样对待它们.)
虽然可怕的代码很糟糕,就像把你带到了破旧的坏代码后面,下面将编译并运行:(至少在我的编译器下.)
bool test( int & a) { return (&a) == (int *) NULL; } int main() { int * i = (int *)NULL; cout << ( test(*i) ) << endl; };
我引用的真正问题在于其他程序员,以下称为IDIOTS,他们在构造函数中分配,在析构函数中解除分配,并且无法提供复制构造函数或operator =().
突然间,foo(BAR bar)和foo(BAR & bar)之间存在着天壤之别.(调用自动按位复制操作.析构函数中的解除分配被调用两次.)
值得庆幸的是,现代编译器将获取同一指针的双重释放.15年前,他们没有.(在gcc/g ++下,使用setenv MALLOC_CHECK_ 0重新访问旧方法.)在DEC UNIX下,在同一内存中分配给两个不同的对象.那里有很多调试乐趣......
更实际的是:
引用隐藏您正在更改存储在其他位置的数据.
将Reference与Copied对象混淆起来很容易.
指针显而易见!