Причина в том, что vector :: resize вставляет копии, вызывая автоматически предоставленный конструктор копирования, а не конструкторы, которые вы определили в своем примере.
Чтобы получить желаемый результат, вы можете явно определить конструктор копирования:
struct C {
//....
C(const C& other) {
id = n++;
// copy other data members
}
//....
};
Из-за того, что vector :: resize работает, хотя (у него есть второй необязательный аргумент, используемый как «прототип» для копий, которые он создает, со значением по умолчанию в вашем случае C()
), это создает 11 объектов в ваш пример («прототип» и 10 его экземпляров).
Изменить (чтобы включить некоторые полезные советы во многих комментариях) :
Существует несколько недостатков этого решения, а также некоторые опции и варианты, которые, вероятно, приведут к более понятному и понятному коду.
Этот метод добавляет затраты на обслуживание и степень риска. Вы должны помнить, чтобы модифицировать ваш конструктор копирования всякий раз, когда вы добавляете или удаляете переменные-члены класса. Вам не нужно этого делать, если вы полагаетесь на конструктор копирования по умолчанию. Одним из способов борьбы с этой проблемой является инкапсуляция счетчика в другом классе ( как этот ), который также, возможно, лучше ОО дизайн, но, конечно, вы также должны иметь в виду многие проблемы которые могут возникать при множественном наследовании .
Это может усложнить понимание для других людей, потому что копия больше не соответствует ожиданиям большинства людей. Точно так же другой код, который работает с вашими классами (включая стандартные контейнеры), может работать неправильно. Одним из способов борьбы с этим является определение метода operator==
для вашего класса (и можно утверждать *1029*, что это хорошая идея при переопределении конструктора копирования, даже если вы не используете метод), сохранить его концептуально «обоснованным», а также как своего рода внутреннюю документацию. Если ваш класс получает широкое применение, вы, вероятно, также в конечном итоге предоставите operator=
, чтобы вы могли поддерживать отделение автоматически сгенерированного идентификатора экземпляра от назначений членов класса, которые должны выполняться в этом операторе. И так далее;)
Это может устранить неоднозначность всей проблемы «различных значений идентификаторов для копий», если у вас достаточно контроля над программой, чтобы использовать динамически создаваемые экземпляры (с помощью новых) и использовать указатели на эти внутри контейнеров. Это означает, что вам нужно до некоторой степени «инициализировать элементы» вручную - но не так много работы, чтобы написать функцию, которая возвращает вам вектор, полный указателей на новые инициализированные экземпляры. Если вы постоянно работаете с указателями при использовании стандартных контейнеров, вам не придется беспокоиться о стандартных контейнерах, создающих какие-либо экземпляры «под прикрытием».
Если вы знаете обо всех этих проблемах и считаете, что можете справиться с последствиями (что, конечно, сильно зависит от вашего конкретного контекста), то переопределение конструктора копирования является жизнеспособным вариантом. В конце концов, языковая особенность есть для причины. Очевидно, это не так просто, как кажется, и вы должны быть осторожны.