Лучший способ - использовать индексы.Честно.Это делает движения и копии просто работают;это очень полезное свойство, потому что при добавлении членов очень легко получить неверное поведение в случае рукописных копий.Закрытая функция-член, которая преобразует индекс в ссылку / указатель, выглядит не очень обременительно.
Тем не менее, могут существовать аналогичные ситуации, когда индексы не являются хорошим вариантом.Если, например, у вас есть unordered_map
вместо vector
, вы, конечно, можете хранить ключи, а не указатели на значения, но тогда вы проходите дорогой хэш.
Если вына самом деле настаиваю на использовании указателей, а не индексов, я бы, вероятно, сделал это:
struct Widget
{
std::vector<int> d_members;
std::vector<int*> d_special_members;
Widget(std::vector<int> members) : d_members(members)
{
for (auto& member : d_members)
if (member % 2 == 0)
d_special_members.push_back(&member);
}
Widget(const Widget& other)
: d_members(other.d_members)
, d_special_members(new_special(other))
{}
Widget& operator=(const Widget& other) {
d_members = other.d_members;
d_special_members = new_special(other);
}
private:
vector<int*> new_special(const Widget& other) {
std::vector<int*> v;
v.reserve(other.d_special_members.size());
std::size_t special_index = 0;
for (std::size_t i = 0; i != d_members.size(); ++i) {
if (&other.d_members[i] == other.d_special_members[special_index]) {
v.push_back(&d_members[i});
++special_index;
}
}
return v;
}
};
Моя реализация работает за линейное время и не использует дополнительного пространства, но использует тот факт (на основе вашего примера кода), что тамповторений в указателях нет, и указатели упорядочены так же, как и исходные данные.
Я избегаю копирования и обмена, потому что нет необходимости избегать дублирования кода и просто для этого нет никаких причин.Это возможный удар по производительности, чтобы получить сильное исключение безопасности, вот и все.Тем не менее, написание универсального CAS, который дает вам надежную исключительную безопасность с любым правильно реализованным классом, тривиально.Создатели классов обычно не должны использовать copy и swap для оператора присваивания (есть, без сомнения, исключения).