【问题标题】:Are const arguments of function are passed by reference automatically?函数的 const 参数是否自动通过引用传递?
【发布时间】:2014-05-29 10:20:27
【问题描述】:

如果我的代码如下所示:

void foofunc(const int fooarg)
{
    // something here
}

fooarg 是通过值传递还是通过引用传递?因为fooarg是const,所以不会被修改,所以引用传递就可以了。


如果我有如下代码:

void foofunc(int fooarg)
{
    // something here, but fooarg is not gonna get modified
}

fooarg 是通过值传递还是通过引用传递,它是否是 const ?情况与上述相同。它不会被修改。

【问题讨论】:

  • 签名没有指定参数是通过引用 (&) 或指针 (*) 传递的,因此它们是按值传递的。为什么这样问?您遇到问题了吗?
  • 当对象通过引用传递时......它们是通过引用传递的。这里没有什么令人困惑的地方,你的论点是按值传递的。
  • @PanagiotisKanavos 我想也许编译器优化了代码:)
  • @PanagiotisKanavos 例如,当我有这样的函数:void foofunc(std:vector<int> v); 并且如果我传递非常大的vector,那么效率会降低:)
  • 不是优化问题。很多时候,您确实想要处理数据的副本——并行处理至少是一种情况。您应该酌情使用引用或复制语义。

标签: c++ constants pass-by-reference pass-by-value


【解决方案1】:

声明说它是按值传递的。所以是按值传递的。

【讨论】:

    【解决方案2】:

    它是按值传递的,因为声明说它是按值传递的。

    它不会被修改,所以通过引用传递就可以了。

    不是这样,但不是这样。另一个线程可能会修改传递的变量。在这种情况下,通过引用传递会改变语义。

    【讨论】:

    • 抱歉这个愚蠢的问题,但你所说的“另一个线程”是什么意思?
    • 我想我明白了。如果我同时运行两个线程,其中一个是foofunc,另一个是修改fooarg 的void wackyfunc(int &fooarg),那么事情就会变得混乱。 :) 谢谢。
    • 即使是单线程,也可以在函数中间修改变量。
    【解决方案3】:

    顶级const 在函数签名中被忽略,因此这些声明完全等效:

    void foofunc(const int fooarg);
    void foofunc(int fooarg);
    

    因此两者的语义都是按值传递的。当然,允许编译器按照“as-if”规则对其进行优化,因此如果有足够的信息,就可以使用引用语义。

    【讨论】:

    • 它们并不完全等价——在第一个函数的主体中,您不能将 fooarg 设置为不同的值,但在第二个函数中可以。
    • 这是真的,但这无关紧要。问题不在于语言级别的函数类型,而在于实现的内部工作原理。
    • @JeremyFriesner 它们是相同的声明。 definition 中的const 表示您不能修改参数的副本。但如果您要提供const 和非const 定义,则会出现多重定义错误。
    • 要么被忽略,要么不被忽略,事实并非如此。这不是无关紧要的。并且即使在某些目的上它们是等价的,这并不意味着它们都是按值传递的。它源于没有'&'。
    • @EJP 除了函数体中的参数 inside 可以做的事情之外,它会被忽略。签名被语言视为相同,因此它们在语义上是等价的。
    【解决方案4】:

    在语言级别,如果您按值传递,那么当然是按值传递,而不是按引用传递。但是如何在底层物理实现传递是一个实现细节,它并不像乍一看那样依赖于 const 的参数。

    在许多编译器实现中,按值传递的“大”参数(从语言的角度来看)实际上是在底层按引用传递的,然后由功能本身。函数体使用副本,它创建了按值接收的参数的最终效果。

    在其他实现中,参数实际上是“按值”传递的,即副本是由调用者提前准备好的。

    前一种方法的优点是知道函数的内部工作原理,编译器可能会在知道不需要复制时决定不进行复制(例如,当函数体不尝试修改参数时)价值)。请注意,无论对应的参数是否声明为const,智能编译器都可以执行此分析并消除不必要的复制。

    这是优化代码生成的问题,不受语言规范的约束。但是,这些问题可能由依赖于平台的 ABI 规范指定。

    【讨论】:

    • "例如当函数体没有尝试修改参数值时" 不仅这个函数没有修改参数,编译器还需要确保调用中传入的变量范围不能在另一个线程上修改,也不能由同一线程上的另一个函数修改。
    猜你喜欢
    • 2013-11-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-19
    相关资源
    最近更新 更多