Раньше я думал, что объектная модель С++ очень надежна, когда соблюдаются лучшие практики.
Всего несколько минут назад, однако, я понял, чего раньше не было.
Рассмотрим этот код:
class Foo
{
std::set<size_t> set;
std::vector<std::set<size_t>::iterator> vector;
// ...
// (assume every method ensures p always points to a valid element of s)
};
Я написал такой код. И до сегодняшнего дня я не видел проблемы с этим.
Но, подумав об этом, я понял, что этот класс очень сломан:
Его copy-constructor и copy-присваивание копируют итераторы внутри vector
, что подразумевает, что они все равно будут указывать на old set
! Новый - это не настоящая копия!
Другими словами, я должен вручную реализовать конструктор-копир, хотя этот класс не управляет никакими ресурсами (без RAII)!
Это кажется мне удивительным. Раньше я никогда не сталкивался с этим вопросом, и я не знаю какого-либо изящного способа его решения. Подумав об этом немного, мне кажется, что построение копии по умолчанию небезопасно - на самом деле мне кажется, что классы не должны копироваться по умолчанию, потому что любая связь между их переменные экземпляра рискуют сделать конструктор-конструктор по умолчанию недопустимым.
Являются ли итераторы принципиально небезопасными для хранения? Или, если классы по умолчанию не подлежат копированию?
Решения, о которых я могу думать ниже, являются нежелательными, поскольку они не позволяют мне использовать автоматически созданный конструктор копирования:
- Вручную создайте конструктор копирования для каждого нетривиального класса, который я пишу. Это не только подверженное ошибкам, но и больно писать для сложного класса.
- Никогда не храните итераторы в качестве переменных-членов. Это кажется строго ограничивающим.
- Отключить копирование по умолчанию для всех классов, которые я пишу, если только я не могу прямо доказать, что они верны. Кажется, что это полностью противоречит С++-дизайну, который для большинства типов имеет семантику значений и, таким образом, может быть скопирован.