Почему появляется следующая ошибка: «возврат ссылки на временный [-Werror = return-local-addr]»

учитывая следующий код:

#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]

Как я могу это исправить?

@Someprogrammerdude Я знаю, что это исправит ошибку (но я не понимаю, почему я не могу вернуть по ссылке в этом случае)

MathQues 26.06.2018 17:06

не возвращая ссылку на временный. s.begin() создает временный объект, и вы возвращаете ссылку на него. Итераторы обычно передаются по значению, поскольку их копировать дешево.

Alan Birtles 26.06.2018 17:06

@AlanBirtles Значит, я не могу вернуть объект из своего набора по ссылке (если я хочу изменить его извне)?

MathQues 26.06.2018 17:07

Вы можете вернуть ссылку на объект (в соответствии с правилами аннулирования итератора), но вы не можете вернуть итератор по ссылке, вы должны вернуться по значению.

Alan Birtles 26.06.2018 17:13

@AlanBirtles Не могли бы вы показать это в новом ответе, пожалуйста :)? (Прошу Iterator& begin();)

MathQues 26.06.2018 17:15

Возможный дубликат C++ Возврат ссылки на временный

Tadeusz Kopec 26.06.2018 17:30
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
6
513
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Функция set<...>::begin возвращает свой итератор по стоимости. Поскольку вы нигде не храните это значение, это значение временный, и у вас не может быть ссылок на временные значения.

Простое решение состоит в том, чтобы ваша функция возвращала также по (неконстантному) значению.

Итак, как я могу разрешить изменять объекты в наборе вне класса?

MathQues 26.06.2018 17:08

@SombreroChicken Вы правы, но в моем классе существует больше метода, который называется begin и возвращает неконстантную ссылку (так что теперь мой вопрос касается этого метода)

MathQues 26.06.2018 17:13

@MathQueus, итератор внутренне ссылается на set <int> s, поэтому, возвращаясь по значению и используя итератор, вы все еще работаете над 's'

rmawatson 26.06.2018 17:17

@rmawatson Но если я верну его по значению, так что это будет только копия действительного элемента в наборе, нет?

MathQues 26.06.2018 17:22

Вы не можете менять объекты в наборе.

Tadeusz Kopec 26.06.2018 17:25

@MathQues, итератор не хранит значение, которое есть в наборе, это просто облегченный тип для итерации по набору. Внутри хранится какая-то ссылка на набор, который вы повторяете. Когда вы разыменовываете итератор, он получает доступ к набору и его значению.

rmawatson 26.06.2018 17:43
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.

Другие вопросы по теме