The problem with a `big_int operator+(big_int lhs, big_int rhs)`
signature is that lvalue arguments cause an unnecessary ref-count
inc+dec, even for basic arithmetic.

You're right. That may have been fine in another library, but does not seem suitable for standardization.
 
Another option is to have a possibly-owning big_int_view type, which
you'd use like `big_int operator+(big_int_view lhs, big_int_view rhs)`.
big_int_view has same layout as big_int, plus an additional "owning"
flag. When initialized from an lvalue (big_int or big_int_view) it
(shallowly) copies the value without taking ownership. When initialized
from an rvalue it copies the value and takes (or inherits) ownership,
clearing the source. This saves you the separate const/rv overloads, and
avoids the extra indirection of a reference.

I feel like the cost of having this whole new view type is higher than just adding a couple of boilerplate overloads.

You also need to consider that operator+ should work if one of the operands is an integer. I think to handle that without avoidable overhead, you actually need operator+ to be a function template. The reason is that for example, __int128 may not fit into big_int without extra allocation, so (big_int + __int128) would require an extra allocation to fit the right side, even though the operation could be performed with only the left allocation involved. I don't think big_int_view can handle the __int128 case in any reasonable way; you cannot do that without ownership.