Копирование (и перемещение) имеют требуемую семантику из-за того, как работает elision, и в меньшей степени из-за того, как работают контейнеры.
Типы значений с хорошим поведением не должны вести себя на удивление иначе, если исключается копирование или перемещение. Они также должны вести себя хорошо при хранении в std::vector
.
Ваше описание во многом похоже на то, как auto_ptr
был взломан как unique_ptr
до того, как у нас была языковая поддержка для перемещения. Это была умная идея, которая превратилась в чудовище плохого, и auto_ptr
является одной из немногих устаревших функций стандартной библиотеки из-за того, насколько плохой она оказалась.
Отделить "состояние" ваших типов от их идентичности. Например, владение - это функция идентификации, а высота - это состояние.
Сохраните состояние в struct
в вашем типе.
Идентификационные данные либо хранятся в вашем типе, либо в другой подструктуре. Подструктура идентификации должна иметь =delete
операций копирования / перемещения.
Предоставить способ создания нового объекта с новым идентификатором, но с тем же состоянием. Если тип объекта - Foo, а его состояние - FooState, то у вас будет явный конструктор Foo(FooState)
.
Иметь метод, который создает копию состояния Foo
.
Не разрешать копирование Foo
. Семантика копирования Foo
, когда идентичность изменяется (очищается) после копирования, является неработоспособной копией семантики . Foo
не подлежит копированию.
Возможна семантика перемещения; в таком случае вы сообщаете своим владельцам об изменении вашего местоположения (через некоторый интерфейс), например:
if (owner)
owner->child_moving( &old, this );
for( auto* child:children )
child->parent_moving( &old, this );
, который позволяет родителям / детям обновлять указатели их владельцев / детей.
Если вы не делаете такого рода вещи, вы не хотите притворяться, что у вас семантика значений; удалите ваши операции копирования / перемещения вместо реализации безумных.