当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《在C++中通过引用传递指针是否有好处?》经验,为你挑选了5个好方法。

在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引用作为参数.

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



1> Johannes Sch..:

通过指针传递

来电者必须拿地址 - >不透明

可以提供0值来表示nothing.这可用于提供可选参数.

通过引用传递

调用者只是传递对象 - >透明.必须用于运算符重载,因为指针类型的重载是不可能的(指针是内置类型).所以你不能 string s = &str1 + &str2;使用指针.

可能没有0值 - >被调用的函数不必检查它们

对const的引用也接受临时性:void f(const T& t); ... f(T(a, b, c));指针不能像那样使用,因为你不能使用临时的地址.

最后但同样重要的是,引用更容易使用 - >错误的机会更少.


我不同意"减少错误的机会".当检查呼叫站点并且读者看到"foo(&s)"时,立即清楚可以修改s.当您阅读"foo(s)"时,如果可以修改s,则一点都不清楚.这是错误的主要来源.也许某类错误的可能性较小,但总的来说,通过引用传递是一个巨大的错误来源.
"透明"是什么意思?
通过指针传递也会提出"是否已转让所有权?" 题.参考不是这种情况.
@ MichaelJ.Davenport - 在你的解释中,你建议使用"透明"来表示"显然调用者正在传递指针,但调用者传递引用并不明显".在约翰内斯的帖子中,他说"通过指针传递 - 来电者必须采取地址 - >不透明"和"通过参考传递 - 来电者只是通过对象 - >透明" - 这几乎与你说的相反.我认为Gbert90的问题"透明"是什么意思仍然有效.
@ Gbert90,如果你在调用网站上看到foo(&a),你知道foo()采用指针类型.如果你看到foo(a),你不知道它是否需要参考.

2> Adam Rosenfi..:

一个指针可以接收一个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的答案以获得完整的答案.

3> Michael Burr..:

艾伦·霍鲁布的"足够的足球射门"列出了以下两条规则:

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

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

它们是定义复制构造函数所必需的

它们是操作员超载所必需的

const 引用允许您在避免复制的同时具有按值传递的语义

他的主要观点是参考不应该用作"输出"参数,因为在呼叫站点没有指示参数是参考还是值参数.所以他的规则是只使用const引用作为参数.

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


我在该论证中的立场是,如果函数名称使得它完全明显,不检查文档,那么param将被修改,那么非const引用就可以了.所以我个人允许"getDetails(DetailStruct&result)".那里的指针引发了NULL输入的丑陋可能性.
我不明白这是多么误导 - 有时需要引用,有时候最佳实践可能会建议不使用它们,即使可以.语言的任何特征都可以这么说 - 继承,非成员朋友,运营商重载,MI等......
这是误导.即使有些人不喜欢引用,它们也是语言的重要组成部分,应该像这样使用.这种推理就像是说不使用模板,你总是可以使用void*的容器来存储任何类型.阅读litb的回答.

4> R. Navega..:

我喜欢"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是否是可接受的值.而已.

毕竟,值是输入,输出,可修改等应该在关于函数的文档/注释中.



5> Mr.Ree..:

澄清前面的帖子:


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

虽然可怕的代码很糟糕,就像把你带到了破旧的代码后面,下面将编译并运行:(至少在我的编译器下.)

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对象混淆起来很容易.

指针显而易见!


这不是函数或引用的问题.你违反了语言规则.取消引用空指针本身已经是未定义的行为."引用并不能保证获得非空指针.":标准本身就是这样.其他方式构成未定义的行为.
无论你对返回的引用做了什么,当你说'*i`时,你的程序都有未定义的行为.例如,编译器可以看到这段代码并假设"好吧,这段代码在所有代码路径中都有未定义的行为,因此整个函数必须是不可达的." 然后它将假定不采用导致此功能的所有分支.这是定期执行的优化.
推荐阅读
大大炮
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有