Обычно при реализации итераторов вы берете итератор вектора или ссылку на вектор:
struct Iter
{
int i = 0;
vector<int>* vec;
Iter(vector<int>& _vec):
vec(&_vec)
{
cout << "copied vector of size "<<vec->size()<<" for iterator\n";
}
int& operator*() { return (*vec)[i]; }
Iter& operator++() { ++i; return *this; }
bool operator!=(const Iter& _it) const { return false; }
};
Таким образом, вы никогда не копируете.
Лучше используйте собственный итератор вектора:
struct Iter
{
vector<int>::iterator it;
Iter(vector<int>::iterator _it):
it(_it)
{ }
int& operator*() { return *it; }
Iter& operator++() { ++it; return *this; }
bool operator!=(const Iter& _it) const { return false; }
};
Но тогда вы можете удалить Iter
и просто использовать векторные итераторы:
struct Factory
{
// ...
auto begin() { return fac_vec.begin(); }
auto end() { return fac_vec.end(); }
};
Теперь, если вы действительно хотите содержать значение внутри итератора (не рекомендуется) .
Компилятор не будет перемещаться fac_vec
, поскольку это lvalue для вектора. Нет движения здесь. Чтобы переместить вектор, вам нужно значение r на вектор.
Это можно получить, перегрузив функцию для эталонного экземпляра rvalue:
struct Factory
{
vector<int> fac_vec;
Factory(const vector<int>& _v):
fac_vec(_v)
{
cout << "copied vector of size " << fac_vec.size() << " for factory\n";
}
Factory(vector<int>&& _v):
fac_vec(move(_v))
{
cout << "moved vector of size "<<fac_vec.size()<<" for factory\n";
}
// moving when Factory is temporary
Iter begin() && { return Iter(std::move(fac_vec)); }
Iter end() && { return Iter({}); }
// copying
Iter begin() const& { return Iter(fac_vec); }
Iter end() const& { return Iter({}); }
};
Но для l oop вызов не будет версия хода. Почему? Это было бы опасно, так как для этого потребовалось бы несколько раз вызывать перемещение для типа.
Диапазон для примерно эквивалентен следующему:
auto&& range = <range expr>; // forwarding reference to range (rvalue in your case)
auto begin = range.begin(); // range is lvalue, so calls the const&
auto end = range.end(); // range is lvalue, so calls the const&
for (/* ... */) {
// body
}
Чтобы использовать ваши операции перемещения, потребуется для приведения диапазона к rvalue несколько раз, возможно, с использованием значения смещения от:
auto begin = std::move(range).begin(); // range is lvalue but moved so calls the &&
auto end = std::move(range).end(); // range is lvalue but moved so calls the &&
Если вы хотите использовать значение в итераторах, что не рекомендуется, вы не можете использовать диапазон для l oop и должны использовать старый стиль для циклов.
Имейте в виду, что вызовы, подобные этому движению, часто воспринимаются как запах кода, а использование многократного перемещения - еще больше.