Should I let objects, whose copying is "costly", be naively copyable?

I'm devising an API - or actually, a wrapper API for another, lower-level API - in a programming language with objects. This API represents some entity E which is reference-counted; but - the reference counting is by the underlying API, or by the OS kernel etc.; so there is an "increase ref count" and "decrease ref count" lower-level functions for these entities. Let's assume we consider the refcount increases/decreases as "expensive" actions. So, I'm designing a class for these entities. An object of class E "holds" one unit of ref count, i.e. we increase the ref count on its construction and decrease it on its destruction. I am now mulling over the reference ownership, copyability and assignability of this class. Let's assume it's copyable if-and-only-if it's assignable and discusss those two features as just "copyability". So, should such E objects be copyable, and how? ... with options I can think about: Make class E naively copyable, supporting e_1 = e_2 statements; the copy code will increase the refcount of the underlying entity (for entity_1) by 1, i.e. do the expensive thing. Make class E movable but not (naively) copyable, i.e. e_2 = e_1 fails; have a E::clone() method Make class E support both owning-reference and non-owning-reference instances, i.e. possibly not increase and decrease the refcount, in which case an instance depends on another, owning, reference to live while being used. In this case, the naive assignment would create a non-owning reference e2 (even if e_1 is an owning reference), without touching the refcount. Separate the notion of ownership from the class, so that E is always a non-owning reference, but we have an owner class template, or generic class, which adds the ownership semantics and from which one can get non-owning E instances. What are the pros and cons you find for each of these options? Notes: I used C++ for my pseudocode, and I am writing this in C++, but if you can answer this more generally, please do. If you need more contextual information to provide an answer, please ask for it, or answer "if X then A, otherwise B".

Jan 17, 2025 - 09:17
Should I let objects, whose copying is "costly", be naively copyable?

I'm devising an API - or actually, a wrapper API for another, lower-level API - in a programming language with objects.

This API represents some entity E which is reference-counted; but - the reference counting is by the underlying API, or by the OS kernel etc.; so there is an "increase ref count" and "decrease ref count" lower-level functions for these entities. Let's assume we consider the refcount increases/decreases as "expensive" actions.

So, I'm designing a class for these entities. An object of class E "holds" one unit of ref count, i.e. we increase the ref count on its construction and decrease it on its destruction.

I am now mulling over the reference ownership, copyability and assignability of this class. Let's assume it's copyable if-and-only-if it's assignable and discusss those two features as just "copyability". So, should such E objects be copyable, and how?

... with options I can think about:

  • Make class E naively copyable, supporting e_1 = e_2 statements; the copy code will increase the refcount of the underlying entity (for entity_1) by 1, i.e. do the expensive thing.
  • Make class E movable but not (naively) copyable, i.e. e_2 = e_1 fails; have a E::clone() method
  • Make class E support both owning-reference and non-owning-reference instances, i.e. possibly not increase and decrease the refcount, in which case an instance depends on another, owning, reference to live while being used. In this case, the naive assignment would create a non-owning reference e2 (even if e_1 is an owning reference), without touching the refcount.
  • Separate the notion of ownership from the class, so that E is always a non-owning reference, but we have an owner class template, or generic class, which adds the ownership semantics and from which one can get non-owning E instances.

What are the pros and cons you find for each of these options?

Notes:

  • I used C++ for my pseudocode, and I am writing this in C++, but if you can answer this more generally, please do.
  • If you need more contextual information to provide an answer, please ask for it, or answer "if X then A, otherwise B".