учитывая следующий код:
#include <set>
using std::set;
class Pool {
set<int> s;
public:
typedef typename set<int>::iterator Iterator;
const Iterator& begin() const {
return s.begin(); //** error
}
};
Почему я получаю следующую ошибку (я понимаю смысл ошибки, но не понимаю, почему я получаю ее в этом случае)?
returning reference to temporary [-Werror=return-local-addr]
Как я могу это исправить?
не возвращая ссылку на временный. s.begin() создает временный объект, и вы возвращаете ссылку на него. Итераторы обычно передаются по значению, поскольку их копировать дешево.
@AlanBirtles Значит, я не могу вернуть объект из своего набора по ссылке (если я хочу изменить его извне)?
Вы можете вернуть ссылку на объект (в соответствии с правилами аннулирования итератора), но вы не можете вернуть итератор по ссылке, вы должны вернуться по значению.
@AlanBirtles Не могли бы вы показать это в новом ответе, пожалуйста :)? (Прошу Iterator& begin();)
Возможный дубликат C++ Возврат ссылки на временный





Функция set<...>::begin возвращает свой итератор по стоимости. Поскольку вы нигде не храните это значение, это значение временный, и у вас не может быть ссылок на временные значения.
Простое решение состоит в том, чтобы ваша функция возвращала также по (неконстантному) значению.
Итак, как я могу разрешить изменять объекты в наборе вне класса?
@SombreroChicken Вы правы, но в моем классе существует больше метода, который называется begin и возвращает неконстантную ссылку (так что теперь мой вопрос касается этого метода)
@MathQueus, итератор внутренне ссылается на set <int> s, поэтому, возвращаясь по значению и используя итератор, вы все еще работаете над 's'
@rmawatson Но если я верну его по значению, так что это будет только копия действительного элемента в наборе, нет?
Вы не можете менять объекты в наборе.
@MathQues, итератор не хранит значение, которое есть в наборе, это просто облегченный тип для итерации по набору. Внутри хранится какая-то ссылка на набор, который вы повторяете. Когда вы разыменовываете итератор, он получает доступ к набору и его значению.
const Iterator& begin() const {
return s.begin(); //** error
}
является незаконным, потому что результатом s.begin() является временный объект, и поэтому вы не можете вернуть ссылку на него. Может, если вы посмотрите на этот эквивалентный код, он станет понятнее?
const Iterator& begin() const {
Iterator it = s.begin();
return it; //** error
}
Возвращение константной ссылки на итератор в любом случае не имеет большого смысла, поскольку вы не сможете переместить место, на которое указывает итератор. Вы всегда должны возвращать итераторы по значению, таким образом вызывающий может делать копии итератора и изменять их местоположение. Например, если бы вы могли заставить свой код скомпилировать следующий вызывающий код, это не сработало бы:
Pool p;
const Pool::Iterator& it = p.begin();
++it; //error it is constant
Пользователь может исправить свой код, скопировав возвращенную вами ссылку в новый объект:
Pool p;
Pool::Iterator it = p.begin();
++it; //no error
Поскольку ваши пользователи не смогут использовать ссылку, вы не можете вернуть ее, лучше просто вернуть по значению:
const Iterator begin() const {
return s.begin();
}
Обратите внимание, что std::set не похож на большинство других контейнеров и не позволяет изменять значения с помощью своих итераторов: https://en.cppreference.com/w/cpp/container/set/begin
Because both iterator and const_iterator are constant iterators (and may in fact be the same type), it is not possible to mutate the elements of the container through an iterator returned by any of these member functions.
@Someprogrammerdude Я знаю, что это исправит ошибку (но я не понимаю, почему я не могу вернуть по ссылке в этом случае)