【问题标题】:Parameter Passing Etiquette (C++) const& vs. value参数传递礼仪 (C++) const 与 value
【发布时间】:2012-05-02 14:53:41
【问题描述】:

如果一个函数只需要查看一个参数的值,你不应该总是通过常量引用来传递那个参数吗?

我的一个同事说小字体没关系,但我不同意。

那么这样做有什么好处吗:

void function(char const& ch){ //<- const ref
    if (ch == 'a'){
        DoSomething(ch);
    }
    return;
}

在此:

void function(char ch){ //<- value
    if (ch == 'a'){
        DoSomething(ch);
    }
    return;
}

在我看来,它们的大小相同:

#include <iostream>
#include <cstdlib>

int main(){

    char ch;
    char& chref = ch;

    std::cout << sizeof(ch) << std::endl; //1
    std::cout << sizeof(chref) << std::endl; //1

    return EXIT_SUCCESS;
}

但我不知道是否总是这样。
我相信我是对的,因为它不会产生任何额外的开销并且是自我记录的。
但是,我想问问社区我的推理和假设是否正确?

【问题讨论】:

  • 您的演示代码似乎表明sizeof(ch)sizeof(ch) 相同——这是您的意图吗?
  • 即使您的意思是sizeof(chref) 用于其中之一,您仍然会得到相同的大小。但这无关紧要,因为当您执行sizeof(chref) 时,它实际上是在告诉您ch 的大小。一旦你初始化了一个引用,对它的所有操作就好像它们实际上是在所指对象上完成的一样。但这并没有告诉你任何关于编译器魔法可能在幕后发生的事情。

标签: c++ reference constants parameter-passing


【解决方案1】:

尽管sizeof(chref)sizeof(ch) 相同,但在大多数系统上,通过引用传递字符确实需要更多字节:尽管标准没有具体说明引用的实现,但地址(即指针)经常在幕后传递。启用优化后,这可能无关紧要。当您编写模板函数时,不会被修改的未知类型的项目应始终通过 const 引用传递。

就小类型而言,您可以使用 const 限定符按值传递它们,以强调您不会通过函数的签名触及参数:

void function(const char ch){ //<- value
    if (ch == 'a'){
        DoSomething(ch);
    }
    return;
}

【讨论】:

    【解决方案2】:

    尺寸与传递的尺寸不同。结果取决于 ABI 调用约定,但 sizeof(referenceVariable) 生成 sizeof(value)

    如果一个函数只需要查看一个参数的值,你不应该总是通过常量引用来传递那个参数吗?

    这就是所做的。我知道人们不同意我的观点,并主张按值传递小型内置函数,或者更愿意省略 const。通过引用传递可以添加指令和/或消耗更多空间。我通过这种方式是为了一致性,因为始终衡量任何给定平台的最佳通过方式是很麻烦的维护。

    除了可读性之外没有其他优势(如果这是您的偏好)。性能可能会受到非常轻微的影响,但在大多数情况下不会考虑。

    通过值传递这些小内置函数更为常见。如果按值传递,您可以const 限定定义(独立于声明)。

    我的建议是,绝大多数团队应该简单地选择一种方式来通过并坚持下去,除非每条指令都很重要,否则性能不应影响这一点。 const 永远不会受到伤害。

    【讨论】:

    • 是的。在 极不可能 事件中(a)您的程序不够快和(b)“不够快”和“足够快”之间的区别是通过引用传递,那么您可以重新访问它。在此之前,最好选择最能传达您的预期含义的内容。
    • @Ben 绝对 +1。我过去曾在一些架构上对其进行过测量,得出的结论是,在高度优化、性能关键的程序中差异并不显着,而我不愿意为这些程序组装。
    【解决方案3】:

    在我看来,您通过 const 引用传递的一般方法是一种很好的做法(但请参阅下面关于您的示例的一些警告)。另一方面,您的朋友是正确的,对于内置类型,按引用传递不应导致任何显着的性能提升,甚至可能导致边际性能损失。我来自 C 背景,所以我倾向于根据指针来考虑引用(即使存在一些细微的差异),并且在我使用的任何平台上,“char*”都会比“char”大熟悉。

    [编辑:删除不正确的信息。]

    在我看来,底线是,当您传递较大的用户定义类型,并且被调用函数只需要读取值而不修改它们时,通过“type const&”传递是一个好习惯。正如您所说,它是自我记录的,有助于阐明内部 API 各个部分的角色。

    【讨论】:

    • 没有const char const &amp; 这样的东西。 const 绑定到它左边的值,除非它是第一个单词,在这种情况下它绑定到它右边的值。所以你说的是char const const &amp;char const &amp; 大致等价于char const * const,也就是说const T &amp; / T const &amp;(同样的东西)不能修改值。
    • 你是对的。自从我不得不用 C++ 处理这个问题已经有好几年了。 IIRC 这可能会编译,但确实是多余的。感谢您的澄清。我认为我最近在 C 语言中使用指针的工作让我失望了。
    • @coydog:如果有误,您应该编辑您的帖子以删除信息,而不是简单地说无视它。
    【解决方案4】:

    对于较小的值,创建引用和取消引用它的成本可能大于复制它的成本(如果有差异的话)。当您考虑到引用参数几乎总是作为指针实现时尤其如此。如果您只是将您的值声明为const(我将此值仅用于输入,它不会被修改),那么这两个文档都一样好。我通常只是将所有标准内置类型设置为const 值,并将所有用户定义/STL 类型设置为const &amp;

    您的sizeof 示例存在缺陷,因为chref 只是ch 的别名。对于任何类型的Tsizeof(T) 都会得到相同的结果。

    【讨论】:

      【解决方案5】:

      你的同事是对的。对于小类型(char、int),当变量不被修改时,通过引用传递是没有意义的。按值传递会更好,因为指针的大小(在按引用传递的情况下使用)大约是小类型的大小。

      此外,按值传递,输入更少,可读性略强。

      【讨论】:

        猜你喜欢
        • 2012-02-25
        • 1970-01-01
        • 2014-06-26
        • 1970-01-01
        • 1970-01-01
        • 2012-05-21
        • 2012-03-07
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多