C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Cheap but Non-Trivial Copy Trait

From: Jason McKesson <jmckesson_at_[hidden]>
Date: Tue, 29 Apr 2025 13:20:05 -0400
On Tue, Apr 29, 2025 at 12:27 PM Yexuan Xiao via Std-Proposals
<std-proposals_at_[hidden]> wrote:
>
> Hey everyone,
>
> I previously wrote a JSON library aiming to precisely represent JSON objects in C++. Recently, I have been contemplating how to optimize its design. In my library, there is a node type that stores an allocator, a type tag, and a union containing arithmetic types and pointers to large objects. Copying it is cheap, and its triviality depends on the allocator. It does not own the objects, behaving like a pointer, allowing arbitrary copies. Today, I realized that the String type could be stored directly as a value within the node instead of storing its pointer, when copying the String is cheap.
> What types of copies are considered cheap? Undoubtedly, all trivially copyable types. However, reference-counted types like Qt’s QString and Windows’ winrt::hstring also exhibit cheap copying, even though their copy-constructors are not trivial. These types typically pointer-sized. If I can efficiently detect such types and store them directly in the node rather than allocating them on the heap and storing pointers, memory allocations could be significantly reduced.
> In other words, a trait that std::string_view, winrt::hstring, and QString satisfy—but std::string does not, would allow generic code to store such types by value without wrapping them in std::unique_ptr or other wrappers. It can be implemented as follows and allows users to specialize:
>
> template<class T>
> struct is_cheap_copy_constructible : is_trivially_copy_constructible{};
> template< class T >
> inline constexpr bool is_cheap_copy_constructible_v =
> is_cheap_copy_constructible<T>::value;
>
> Any feedback is welcome.

Without some kind of clear definition of what "cheap" means, this is
not really a viable proposal. As Paul pointed out, trivially copyable
objects can be of gargantuan size yet would still be considered
"cheap" to copy when it very much is not.

It seems to me that when you say "cheap", what you really mean is
"non-allocating". `noexcept` on the copy constructor is a pretty good
indicator that it is not allocating. Beyond that, I feel like this is
something you could use a traits class or similar to allow a person to
tell you that their type is "cheap" to copy. That way, you can spell
out *specifically* what this interface is looking for in designating a
type to be "cheap" to copy.

Especially since not all allocators are expensive. If I'm using a
`monotonic_buffer_resource` to allocate storage for some object's
internals, I may feel justified in telling your API that copies are
"cheap".

Received on 2025-04-29 17:20:18