XPerf
LanguagesC++Evidence

cx-const-by-value — measured, still hint

Status

hint. Wall-clock JSONL: cx-const-by-value.jsonl. Not corpus-triaged. The 2026-10-22 corpus verdict does not cover this slug.

Measurement

clang++ -std=c++17 -O2 (Apple clang version 21.0.0 (clang-2100.1.1.101)). Parameter cases call a function in another translation unit, so the copy is the one the ABI makes. Each side returns size + first byte (or size + first int). The harness sums that return across 9 timed rounds after 3 warmups. Checksums matched. After times stayed above 0.

rolecasemedian_msopsratio
afterone int in a vector, const reference0.1484172000001
beforeone int in a vector, const by value2.47100020000016.649
after64-byte string, const reference0.039792400001
before64-byte string, const by value0.6107094000015.348
afterrange-for of 128-byte strings, const reference0.016042200001
beforerange-for of 128-byte strings, const by value0.3297082000020.553
afterrange-for of 64-int vectors, const reference0.00570880001
beforerange-for of 64-int vectors, const by value0.122083800021.388

Same shape, also above the bar, not repeated in the JSONL: a 23-byte string parameter was 16.728× (1.700666 / 0.101667 ms, 100000 ops), 32 bytes 17.504× (1.423625 / 0.081333 ms, 80000), 256 bytes 22.681× (0.462125 / 0.020375 ms, 20000), 4096 bytes 59.952× (1.206541 / 0.020125 ms, 20000). A 4-int vector was 16.145× (2.396875 / 0.148458 ms, 200000). A 1024-int vector, touching the first element, was 74.110× (1.120916 / 0.015125 ms, 20000).

A same-file 4096-byte touch, with a volatile zero added so the reference loop could not disappear, was 115.971× (1.178958 / 0.010166 ms, 20000). Inlining did not remove that copy.

Limits

These stayed under the bar. The scanner still flags the spelling, because it cannot see the length or the body:

casebefore_msafter_msopsratio
4-character string parameter0.3038340.3012503000001.009
empty vector parameter0.3710000.3033343000001.223
64-byte string, sum every byte0.3565830.081708200004.364
4096-byte string, sum every byte0.9803750.76762540001.277
range-for of 4-character strings0.0202920.010625400001.910
1024-int vector, sum every element0.3241250.15191740002.134

The matcher is one line: const std::string / const std::vector<...> (and the east-const spelling) whose name is followed by , or ), plus the same types in a for ( head before :. It misses const auto, a name on the next line, a default argument (=), and a nested >>. A non-const by-value parameter is left alone: on a 4096-byte string that copy was 60.510× (1.235375 / 0.020416 ms, 20000 ops), and it is also how a function takes ownership. A local const std::string copy = ... is left alone.

Default stays hint. These ratios are not a general speedup.

Unblock

Do not set the default to error from this file alone. A short string, an empty vector, or a body that reads every element can erase the difference. Corpus triage is still required before any default change.