CppCoreGuidelines icon indicating copy to clipboard operation
CppCoreGuidelines copied to clipboard

F.16 what exactly is cheap to copy for the purposes of passing "by value"?

Open palotasb-conti opened this issue 6 years ago • 10 comments

F.16 says:

What is “cheap to copy” depends on the machine architecture, but two or three words (doubles, pointers, references) are usually best passed by value.

I need clarification on what the guidelines mean by "two or three words". I have two conflicting interpretations:

  • 1 word == sizeof one double, pointer or reference and thus objects two or three times this size should generally be passed by value (such as string_view or shared_ptr)
  • "two or three words" is the sizeof one double, pointer or reference and thus anything larger than that should be passed by reference.

I find the first interpretation more logical. Can the text be clarified? Do you accept PRs for fixing this and clarifying that the first interpretation is correct?

palotasb-conti avatar May 09 '19 15:05 palotasb-conti

A word is commonly two bytes, but the important part of the statement you quoted is that you can't give an exact number, because the cost it depends on the details of the ABI and architecture.

Keep also in mind, that often the "cost" of copying bits is much less important than how it effects optimization.

Btw. Copying a shared pointer is pretty expensive, because you are not just copying two pointers but also increment the counter, which lives somewhere else in memory.

MikeGitb avatar May 09 '19 16:05 MikeGitb

I think the Enforcement section in that same guideline makes it clear:

(Simple) ((Foundation)) Warn when a parameter being passed by value has a size greater than 2 * sizeof(void*). Suggest using a reference to const instead. (Simple) ((Foundation)) Warn when a parameter passed by reference to const has a size less than 2 * sizeof(void*). Suggest passing by value instead.

(come to think of it, this could be improved to only suggest by-value for trivially-copyable types)

cubbimew avatar May 09 '19 17:05 cubbimew

@MikeGitb two bytes?

jwakely avatar May 09 '19 18:05 jwakely

Editors call: We think the Enforcement gives a clear size, but agree with @cubbimew that the Enforcements (and probably the Guideline) should additionally be triggered only when the type is trivially copyable. For example, a container object may be that small, but it can own lots of objects and be not cheap to copy.

hsutter avatar May 09 '19 18:05 hsutter

Sorry, was thinking in windows terms.

MikeGitb avatar May 09 '19 19:05 MikeGitb

Thank you Sergey @cubbimew and Herb @hsutter, you answered my question. The trivial copyability should probably be a separate issue, thanks for pointing that out @MikeGitb.

palotasb-conti avatar May 10 '19 11:05 palotasb-conti

Could the word "references" be removed from this specific sentence:

[...] two or three words (doubles, pointers, references) are usually best passed by value.

Otherwise, is the intention to specifically recommend passing references by value, rather than by reference? If so, could it be explained what it means to pass references "by reference"? Isn't that dealt with by reference collapsing?

Should I make a separate pull request to remove the word "references"?

N-Dekker avatar Jun 03 '22 10:06 N-Dekker

I think thats about a struct that has a reference as a member. EDIT: But I agree, that - even if I'm right - some clarification would be useful.

MikeGitb avatar Jun 03 '22 12:06 MikeGitb

I think thats about a struct that has a reference as a member

Thanks @MikeGitb I guess you're right. Maybe the sentence could be clarified by adding the word "struct". But then, I don't really understand why doubles, pointers, and references are specifically mentioned here. Integers would also be fine, right? To avoid any confusion, I would then rather simply just remove "(doubles, pointers, references)" from the sentence. What do you think?

On the other hand, I think it would be helpful to explicitly mention that fundamental types are considered cheap-to-copy: https://github.com/isocpp/CppCoreGuidelines/issues/1784#issuecomment-1145300480

N-Dekker avatar Jun 03 '22 13:06 N-Dekker

Thanks again, so what do you think of the following adjustment?

What is “cheap to copy” depends on the machine architecture, but an argument of a fundamental type, an enumeration type, or a raw pointer type is usually best passed by value. The same is true for an object of a trivially copyable class type, at least as long as it is small enough (having a compile-time size of up to 2 * sizeof(void*), typically).

Instead of: https://github.com/isocpp/CppCoreGuidelines/blob/ddef6cdbaeba9ec70e58e52eeb54635c0f3f0804/CppCoreGuidelines.md?plain=1#L2901

So as a guideline, I would suggest to pass an argument of even the largest fundamental type (possibly intmax_t or long double), or the largest raw pointer-to-member-function type by-value. Would that be OK?

N-Dekker avatar Jun 03 '22 21:06 N-Dekker