简体   繁体   English

参数传递礼仪(C ++)const&vs. value

[英]Parameter Passing Etiquette (C++) const& vs. value

If all a function needs to do with a parameter is see its value, shouldn't you always pass that parameter by constant reference? 如果函数需要的所有函数都看到它的值,那么你不应该总是通过常量引用传递该参数吗?

A colleague of mine stated that it doesn't matter for small types, but I disagree. 我的一位同事表示,对于小类型来说无关紧要,但我不同意。

So is there any advantage to do this: 这样做有什么好处:

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

over this: 对此:

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

They appear to be the same size to me: 它们看起来和我一样大小:

#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;
}

But I do not know if this is always the case. 但我不知道是否总是如此。
I believe I'm right, because it does not produce any additional overhead and it is self documenting. 我相信我是对的,因为它不会产生任何额外的开销,而且它是自我记录的。
However, I want to ask the community if my reasoning and assumptions are correct? 但是,我想问社群我的推理和假设是否正确?

Your colleague is correct. 你的同事是对的。 For small types (char, int) it makes no sense to pass by reference, when the variable is not to be modified. 对于小类型(char,int),当不修改变量时,通过引用传递是没有意义的。 Passing by value would be better, as size of pointer (used in case of passing by reference) is about the size of small types. 传递值会更好,因为指针的大小(在通过引用传递的情况下使用)大约是小类型的大小。

And moreover, passing by value, is lesser typing, as well as slightly more readable. 而且,按值传递,输入较少,并且可读性稍差。

Even though the sizeof(chref) is the same as sizeof(ch) , passing character by reference does take more bytes on most systems: although the standard does not say anything specific about the implementation of references, an address (ie a pointer) is regularly passed behind the scenes. 即使sizeof(chref)sizeof(ch)相同,通过引用传递字符在大多数系统上也需要更多的字节:虽然标准没有说明有关引用实现的任何特定内容,但地址(即指针)是经常在幕后传递。 With optimization on, it probably would not matter. 通过优化,它可能无关紧要。 When you code template functions, items of unknown type that will not be modified should always be passed by const reference. 编写模板函数时,不应修改的未知类型的项应始终通过const引用传递。

As far as small types go, you can pass them by value with a const qualifier to emphasize the point that you aren't going to touch the argument through the signature of your function: 对于小类型,您可以使用const限定符按值传递它们,以强调您不会通过函数的签名触及参数:

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

For small values, the cost of creating a reference and dereferencing it is likely to be greater than the cost of copying it (if there is a difference at all). 对于较小的值,创建引用和取消引用它的成本可能大于复制它的成本(如果存在差异)。 This is especially true when you consider that reference parameters are pretty much always implemented as a pointer. 当您考虑参考参数几乎总是作为指针实现时,尤其如此。 Both document equally well if you just declare your value as const (I'm using this value for input only and it will not be modified). 如果你只是将你的值声明为const (我只使用这个值作为输入而且它不会被修改),那么两个文档都同样好。 I generally just make all of the standard built-in types by const value and all user-defined / STL types as const & . 我通常只使用const值和所有用户定义的/ STL类型将所有标准内置类型作为const &

Your sizeof example is flawed because chref is just an alias for ch . 你的sizeof示例存在缺陷,因为chref只是ch的别名。 You'd get equal results for sizeof(T) for any type T . 任何类型T sizeof(T)都会得到相同的结果。

The sizes are not the same as passed. 大小是一样的通过。 The result depends on the ABIs calling convention, but the sizeof(referenceVariable) produces the sizeof(value) . 结果取决于ABI调用约定,但sizeof(referenceVariable)生成sizeof(value)

If all a function needs to do with a parameter is see its value, shouldn't you always pass that parameter by constant reference? 如果函数需要的所有函数都看到它的值,那么你不应该总是通过常量引用传递该参数吗?

That's what I do. 这就是我的工作 I know people disagree with me, and argue for passing small builtins by value, or prefer to omit the const . 我知道人们不同意我的观点,并且主张通过值传递小内置函数,或者更喜欢省略const Passing by reference can add instructions and/or consume more space. 通过引用传递可以添加指令和/或消耗更多空间。 I pass this way for consistency , and because always measuring the best way to pass for any given platform is a lot of hassle to maintain. 我通过这种方式保持一致性 ,因为总是测量任何给定平台的最佳传递方式是很难维护的。

There isn't an advantage beyond readability (if that's your preference). 没有超出可读性的优势(如果这是您的偏好)。 Performance could suffer very slightly , but it will not be a consideration in most cases. 性能可能会受到轻微影响 ,但在大多数情况下不会考虑。

Passing these small builtins by value is more common. 按值传递这些小内置更常见。 If passing by value, you can const qualify the definition (independent of the declaration). 如果通过值传递,则可以使const限定定义(独立于声明)。

My recommendation is that the vast majority of teams should simply choose one way to pass and stick with it, and performance should not influence that unless every instruction counts . 我的建议是,绝大多数团队应该只选择一种方式来传递并坚持下去,除非每一条指令都重要 ,否则表现不应影响到这一点。 The const never hurts. const永远不会伤害。

In my opinion, your general approach of passing by const reference is a good practice (but see below for some caveats on your example). 在我看来,你通过const引用的一般方法是一个很好的做法(但请参阅下面的例子中的一些警告)。 On the other hand, your friend is correct that for built-in types, passing by reference should not result in any significant performance gains, and could even result in marginal performance losses. 另一方面,您的朋友是正确的,对于内置类型,通过引用传递不应导致任何显着的性能提升,甚至可能导致边际性能损失。 I come from a C background, so I tend to think of references in terms of pointers (even though there are some subtle differences), and a "char*" will be bigger than a "char" on any platform with which I'm familiar. 我来自C背景,所以我倾向于考虑指针的引用(即使有一些细微的差别),并且“char *”将比任何平台上的“char”更大熟悉。

[EDIT: removed incorrect information.] [编辑:删除了不正确的信息。]

The bottom line, in my opinion, is that when you're passing larger user-defined types, and the called function only needs to read values without modifying them, passing by "type const&" is a good practice. 在我看来,底线是当你传递更大的用户定义类型时,被调用的函数只需要读取值而不修改它们,传递“type const&”是一个很好的做法。 As you say, it's self-documenting, and helps clarify the roles of the various pieces of your internal API. 正如您所说,它是自我记录的,并有助于阐明内部API的各个部分的角色。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM