按值传递/指针/引用说明

Posted

技术标签:

【中文标题】按值传递/指针/引用说明【英文标题】:Pass By Value/Pointer/Reference Clarification 【发布时间】:2014-09-08 01:40:50 【问题描述】:

我需要对按值/指针/引用传递的一劳永逸的说明。

如果我有一个变量,例如

int SomeInt = 10;

我想将它传递给类似的函数

void DoSomething(int Integer)

    Integer = 1;

在我当前的情况下,当将 SomeInt 传递给 DoSomething() 时,我希望 SomeInt 的值根据我们在 DoSomething() 中对其所做的任何事情进行更新,并且在内存和性能方面最有效,所以我没有复制周围的变量?话虽如此,以下哪些原型可以完成这项任务?

void DoSomething(int* Integer);
void DoSomething(int& Integer);

我如何将变量实际传递给函数?前两个原型有什么区别?

最后,如果在类中使用函数

class SomeClass

    int MyInteger;

public:
    void ChangeValue(int& NewValue)
    
        MyInteger = NewValue;
    
;

如果我将一个整数传递给 ChangeValue,当我传入 get 的整数被删除时,这是否意味着当我尝试在类中使用 MyInteger 时,它将不再可用?

感谢大家的宝贵时间,我知道这是一个基本问题,但我不断遇到的解释让我更加困惑。

【问题讨论】:

是的,这些功能可能会完成任务。 -1 我有兴趣了解人们如何在不看基本学习材料的情况下学习像 C++ 这样复杂的编程语言。 您可能有兴趣阅读FAQ问题***.com/questions/2139224/… 【参考方案1】:

从功能上讲,这三个都有效:

传递int将返回类型更改int,这样您就可以返回新值,用法:x = f(x);

当您打算设置值时不需要读取初始值,最好使用像int DoSomething(); 这样的函数,这样调用者就可以说@ 987654325@ 无需在前面的行上创建 x 并且想知道/担心是否需要在调用之前将其初始化为任何内容。

传递一个int&并将其设置在函数内部,用法:int x; x = ? /* if an input */; f(x);

传递一个int*并在函数内部设置指向int,用法:int x; x = ?; f(&x);

在内存和性能上最有效,所以我不会复制变量

鉴于 C++ 标准并未规定编译器应如何实现引用,因此尝试推理它们的特性有点可疑 - 如果您关心将代码编译为汇编代码或机器代码并查看它在您的特定的编译器(用于特定的编译器命令行选项等)。如果您需要经验法则,请假设引用具有与指针相同的性能特征,除非分析或生成代码检查另有建议。

对于int,您可以期望上面的第一个版本不会比指针版本慢,并且可能更快,因为int 参数可以无需内存地址即可在寄存器中传递和返回。

如果/何时/在哪里逐指针版本是内联,那么潜在的缓慢“需要一个内存地址以便我们可以传递一个指针”/“必须取消引用一个指针才能访问”的可能性更大/update the value" 可以优化传递指针版本的方面(如果您已要求编译器尝试),使两个版本具有相同的性能....

不过,如果您需要问这样的问题,我无法想象您正在编写代码,其中这些是重要的优化选择,因此更好的目标是为您提供最简洁、最直观和稳健的用法对于客户端代码......现在 - 无论是x = f(x);(您可能会忘记前导x =),还是f(x),您可能没有意识到x可以被修改,或者f(&x)(其中一些调用者可能认为他们可以通过nullptr 本身是一个合理的问题,但与您的性能问题不同。FWIW,C++ FAQ Lite 建议在这种情况下引用指针而不是指针,但我个人拒绝它的推理和结论 - 它一切都归结为熟悉任一约定,以及您需要多久传递一次const 指针值或nullptr 是有效标记的指针值,这可能与您希望的you-may-modify-me 含义相混淆在您的情况下...这在很大程度上取决于您的编码风格、你使用的库、问题领域等。

【讨论】:

谢谢。我一直在我的应用程序中到处传递指针,但是我最近遇到了轻微的性能下降,并且希望 100% 清楚指针/引用以及如何避免在函数调用期间不惜一切代价复制变量。跨度> 不客气。当您传递复制速度较慢的大型对象时,通过指针或引用传递可能很有用,但鉴于int 不大于并且可能小于指针,它对int 没有帮助。请尝试使用分析器(例如 g++/VC++ 有内置分析器、ValGrind 等)——这可能会出现各种意想不到的事情,从而产生更大的影响。【参考方案2】:

你的两个例子

void DoSomething(int* Integer);
void DoSomething(int& Integer);

将完成任务。在第一种情况下 - 使用指针 - 您需要使用 DoSomething(&SomeInt); 调用函数,在第二种情况下 - 使用引用 - 更简单为 DoSomething(SomeInt);

推荐的方法是在足够的时候使用引用,只在必要时使用指针。

【讨论】:

好的,非常感谢,最后一件事,您能看看问题中的类示例吗? @KKlouzal “如果我将一个整数传递给 ChangeValue,当我传入 get 的整数被删除时,这是否意味着当我尝试在类中使用 MyInteger 时,它将不再可用?” - 你不能“删除”一个整数。 MyInteger 只是获得了一个新值,但以后完全可以使用。【参考方案3】:

你可以使用任何一个。第一个原型的函数调用将是

DoSomething(&SomeInt);  

对于第二个原型

DoSomething(SomeInt);  

【讨论】:

【参考方案4】:

如前所述,您可以同时使用两者。

的优势
void DoSomething(int* Integer)

  *Integer=0xDEADBEEF;

DoSomething(&myvariable);

模式是,从调用中可以明显看出 myvariable 可能会发生变化。

优点

void DoSomething(int& Integer)

  Integer=0xDEADBEEF;

DoSomething(myvariable);

模式是 DoSomething 中的代码更干净一些,DoSomething 很难以不好的方式弄乱内存,并且您可能会从中获得更好的代码。缺点是从读取调用中并不能立即看出 myvariable 可能会被更改。

【讨论】:

如果您关心myvariable 被更改,那么它应该已经是const 如果你有i=0这样的情况;做某事(一);我++; i 不能是 const,你非常关心 i 是否改变。 所以不要那样做...您的代码已损坏。当i 不是const 时,您将i 传递给您不想修改i 的函数。设计很差。

以上是关于按值传递/指针/引用说明的主要内容,如果未能解决你的问题,请参考以下文章

按值传递指针和引用之间的区别?

是否传递指针参数,在 C++ 中按值传递?

java的按值传递与按引用传递

C++:为啥对于内置(即类 C)类型,按值传递通常比按引用传递更有效

我应该在哪里更喜欢按引用传递或按值传递?

js按值传递和按引用传递