Требование «CopyConstructible» для элемента контейнера stl C ++ - PullRequest
9 голосов
/ 30 июня 2011

Что касается требования к контейнерному элементу C ++ stl, то в стандарте сказано: тип элемента должен быть CopyConstructible, и есть таблица требований CopyConstructible. Также по различным книгам (Josuttis и т. Д.) Сгенерированная копия должна быть «эквивалентна» источнику.

Я думаю, мне нужна ясность здесь. Что именно "эквивалентно"? Также меня немного смущает связь между «CopyConstructible» и «глубокой / мелкой копией». В общем случае конструктор копирования является либо поверхностным, либо глубоким копированием. Так какой же из них относится к «CopyConstructible», а какой нет?

Спасибо за любые комментарии!

Ответы [ 6 ]

8 голосов
/ 30 июня 2011

Глубокая или мелкая копия обе работы. Например, shared_ptr всегда делает поверхностную копию (с некоторыми дополнительными подсчетами ссылок), и вы можете использовать их в контейнерах просто отлично. Это зависит от семантики операции копирования.

Эквивалент означает, что ваша программа не должна зависеть от того, работает ли она с оригиналом или с копией.

6 голосов
/ 30 июня 2011

Если вы поместите что-то в контейнер, когда вы получите его, вы получите что-то, что эквивалент тому, что вы положили. Пока это имеет значение для ваших объектов, вы получите что-то полезное из контейнера.

Является ли это мелкой или глубокой копией, зависит от семантики, которую вы хотите для своего типа объекта. Ваш объект может быть в виде указателя, дескриптора или, возможно, контейнера. Он может содержать некоторые изменяемые данные кэша, которые вы можете или не можете дублировать в операции копирования.

Пока ваш конструктор копирования доступен и делает все, что вам нужно для сохранения семантики типа вашего объекта, вы удовлетворяете требованию CopyConstructible .

2 голосов
/ 30 июня 2011

Как правило, контейнеры STL могут копировать ваши элементы на каком-то этапе, во время некоторых операций или алгоритмов, поэтому лакмусовый тест выглядит следующим образом:

Element original(....);  // construct this awesome object
original.this_and_that();  // do stuff to it until the value is perfect...

Element another(original);

Не могли бы вы с удовольствием использовать anotherвместо original?

Это действительно то, что говорится в требовании CopyConstructible: вам лучше иметь возможность скопировать это в другой объект и при этом быть довольным результатом.Это не драконовское ограничение - вам просто нужно продумать и написать соответствующий конструктор копирования.

Но важно то, что некоторые операции, такие как find(), могут использовать == для сравнения элементов (для других контейнеров, это может быть '<'), поэтому <strong>если побочным эффектом копирования является невозможность значительного сравнения элементов, то ваши find s и др. могут перестать работать - подумайте об этом слишком!(Стандарт говорит для контейнеров: «== - отношение эквивалентности» (23.1-5).)

1 голос
/ 30 июня 2011

Думать, что «конструктор копирования выполняет глубокое или поверхностное копирование», это немного ограничивает, что-то вроде красной сельди.

Хотя это правда, что в зависимости от того, что ваш объект хранит в качестве членов, вам может потребоваться выполнить глубокое копирование, чтобы получить эквивалентность, что касается интерфейса типа , это не так. * действительно важно как вы выполняли копирование ... до тех пор, пока вы выполняли копирование и вы получили эквивалентный объект.

А если A эквивалентно B, то для правильно разработанного типа A==B.

Все требование просто гласит: «тип элемента должен быть копируемым». Все остальное сводится к обычному здравому смыслу написания правильного конструктора копирования.

0 голосов
/ 30 июня 2011

Здесь обсуждается пара различных концепций.CopyConstructible требует только того, чтобы вы могли создать новый элемент этого типа, используя существующий элемент в качестве источника для копирования.Он не имеет отношения к deep или shallow или даже эквивалентности : контейнеру все равно, что вы делаете во время копирования, если ему разрешено выполнять эту копию.

Вторым понятием является понятие эквивалентность , когда вы используете объект в контейнере, он будет скопирован, а количество выполненных копий неизвестно - реализация может скопировать еготолько один раз, чтобы сохранить его внутри, или он может сделать несколько копий внутри.То, что вы хотите, - это возможность извлечь элемент из контейнера и использовать его, как если бы он был исходным объектом, вот где приходит эквивалентность : n-я копия, котораяВы извлекаете , должно быть эквивалентным вставленному вами объекту.

Понятия deep и shallow непосредственно связаны с эквивалентность , в зависимости от моделируемого домена, эквивалентность может потребовать либо мелкое , либо глубокое копирование, и в зависимости от других ограничений вам может потребоваться выбрать одно или другое -- если в вашем домене они эквивалентны - или могут быть даже промежуточные варианты, когда выполняется частично глубокое копирование, или некоторые элементы вообще не копируются.

0 голосов
/ 30 июня 2011

Связанный пост: В чем разница между равенством и эквивалентностью?

Отредактировано, чтобы сделать это "без комментариев".

Эквивалентность означает «равный для всех намерений и целей». Например: 1.0001 и 1 никогда не равны, но при определенных обстоятельствах они эквивалентны. Это общий ответ.

Что означают книги, так это то, что скопированные объекты должны удовлетворять строгому условию слабого упорядочения с исходным объектом: copy < original == false && original < copy == false.

...