parts/6.38.DeepVsShallowCopying-YAN.md

6.38 Deep vs. Shallow Copying [YAN]

6.38.1 Applicability to Language

The vulnerability described in ISO/IEC TR 24772-1:2019 clause 6.38 exists in C++ and only arises in C++ when there is a mismatch between the type’s copy semantics and the programmer’s intent.

On the language level, reference semantics, that can lead to shallow copies, usually requires the use of pointer or reference types, however, an integral type can also have reference semantics, for example, when it is used as an index or as an operating system handle.

Such types with reference semantics are also called relationship types and they will suffer from the aliasing problematic of this vulnerability and additionally from potential dangling due to expired lifetime of referred objects (see [XYK]).

In general, relationship types with an immutable referent, such as a const-reference, do not suffer the deep vs. shallow copying semantics problem, unless mixed with relationship types with a mutable reference to the same object. However, the lifetime of a const referent is still an issue to manage (see [XYK]).

The standard library type std::shared_ptr<T> has shallow copy semantics when the managed type is non-const, but in contrast to other relationship types guarantees the lifetime of the referent.

Class types that have relationship type members will become relationship types themselves, unless the class provides deep copy semantics or disables it and manages the lifetime of the referred object (manager type). Such relationship types and manager types will refer to their referred/managed resources via a data member with reference semantics.

A manager type defines a non-empty, non-deleted destructor in addition to providing appropriate copy and move operations. Examples of a manager types are the standard library container types such as std::vector that use pointers to the allocated space of their elements and copying a vector will also copy all contained elements not just the pointers. This management is achieved by replacing the compiler-provided copy-constructor and copy-assignment operator with implementations providing value semantics that perform the deep copy (general manager). An alternative to potentially expensive deep copies for manager types is the prevention of copying, either by defining move operations that transfer the ownership of a managed resources, like std::unique_ptr does (unique manager), or by preventing both copy and move operations (scoped manager), for example, by defining the move-assignment operator as deleted.

Without such replacement of copy and move operations a class type with relationship type members suffers from the potential confusion due to shallow copies. For example, the standard library types std::span, std::string_view, iterators, and the views of the standard ranges library are relationship types. Care must be taken to not only understand implications of their shallow copy semantics, but also about their validity depending on the lifetime of the referred ranges.

Using relationship types as function parameter types is usually safe, because language semantics guarantee the lifetime of parameter objects. Exceptions exists for thread functions and coroutines, where the initial calling context is not guaranteed to exist when parameters of relationship type are accessed.

Returning a relationship type from a function can be problematic, unless the lifetime of the referred object is clear. For example, returning a reference to a local variable will return a dangling reference (see [XYK] and [XYH]).

See also Core Guidelines C.20, C.22, C.32, C.67.

6.38.2 Avoidance mechanisms for language users

To avoid the vulnerability or mitigate its ill effects, C++ software developers can: