Как вернуть ссылку unique_ptr на константный тип

Мне бы хотелось, чтобы функция-член возвращала ссылку unique_ptr на константный тип, как в необработанных указателях.

Вот что я имею в виду:

class Foo {
   private:
      int _number;

   public:
      [[nodiscard]] explicit Foo(int number) : _number(number) {}
      [[nodiscard]] int number() const { return _number; }
      void set_number(int number) { _number = number; }
};

class ManageFoo {
   private:
      std::unique_ptr<Foo> foo_ptr;

   public:
      explicit ManageFoo(std::unique_ptr<Foo> &&foo_ptr) : foo_ptr(std::move(foo_ptr)) {};

      void set_number(const int &number) {
         foo_ptr->set_number(number);
         // And perform something else...
      }

      const Foo *getFoo() { return foo_ptr.get(); }
};

Я хочу, чтобы пользователь ManageFoo менял состояние Foo только через ManageFoo set_number. Вот почему я хочу, чтобы getFoo возвращал указатель на const Foo. Я хочу, чтобы пользователь имел доступ только к версии Foo, доступной только для чтения. Чтобы избежать использования foo_ptr.get(), можно ли написать getFoo возвращающий std::unique_ptr<const Foo>& ?

const Foo *getFoo() const { return foo_ptr.get(); } — идеальный добытчик. Какую пользу от возвращения std::unique_ptr<const Foo>& вы ожидаете?
3CxEZiVlQ 22.08.2024 23:54

Ваша просьба кажется ошибкой. Возврат std::unique_ptr уместен только при передаче права собственности. В вашем случае похоже, что ManageFoo продолжает оставаться владельцем. Если ManageFoo::foo_ptr остается действительным, он должен быть единственным существующим unique_ptr (это означает уникальность).

Ben Voigt 22.08.2024 23:55

Однако я мог бы рассмотреть возможность добавления const Foo* operator->() const и const Foo& operator*() const либо вместо getFoo(), либо в дополнение.

Ben Voigt 22.08.2024 23:56

Также обратите внимание, что если вам удалось получить unique_ptr<const Foo>& getFoo(), вызывающая сторона могла бы сделать mfoo.getFoo().reset(new Foo(42)), заменив весь объект Foo на наш из-под ManageFoo. Указатель на константу — это не то же самое, что константный указатель, и это справедливо и для интеллектуальных указателей.

Ben Voigt 23.08.2024 00:01

Почему бы просто не вернуться const Foo*?

Galik 23.08.2024 00:07

Меня беспокоит то, что если я выставлю необработанный указатель, пользователь может попытаться удалить его где-то еще. Последнее наблюдение Фойгта интересно: мой запрос должен быть «const unique_ptr<const Foo>& getFoo()» !!

rdabra 23.08.2024 00:07

Раньше я возвращал unique_ptr ссылки, потому что считал, что они добавляют ясности. Поговорив с другими программистами, использующими мой код, я убедился, что это мало что добавляет, кроме боли. Теперь я возвращаю необработанные указатели, когда право собственности не передается, и доверяю своим коллегам, что они не выстрелят себе в ногу необработанными указателями.

user4581301 23.08.2024 00:08

В современном C++ никто не должен удалять необработанные указатели. (если вы не пишете свой собственный умный указатель).

Galik 23.08.2024 00:09

пользователь может попытаться удалить его где-то еще — такой пользователь даже не остановится на delete foo.get().

3CxEZiVlQ 23.08.2024 00:14

Поскольку можно вернуть «const Foo*» из «Foo*», не было бы неплохо иметь это также и в unique_pointers? Что вы думаете?

rdabra 23.08.2024 00:21

Вы говорите о свойстве const-propagation, которого в настоящее время нет ни у одного из стандартных интеллектуальных указателей. Да, это свойство может быть желательным, но оно противоречит тому факту, что вам не следует передавать или возвращать unique_ptr, за исключением намеренной передачи права собственности.

Useless 23.08.2024 00:43

«Меня беспокоит то, что если я выставлю необработанный указатель, пользователь может попытаться удалить его где-то еще». -- Если вы откроете объект, пользователь может попытаться удалить его где-нибудь еще. Не имеет значения, возвращаете ли вы интеллектуальный указатель, необработанный указатель или ссылку; если пользователь может получить доступ к объекту напрямую, адрес доступен и может быть передан delete. Это не твоя проблема. C++ не является безопасным языком для тех, кто хочет нарушить условности.

JaMiT 23.08.2024 02:49
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать 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
12
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий
void set_number(const int &number) {
  foo_ptr->set_number(number);
  // And perform something else...
}

foo_ptr, кажется, никогда не становится нулевым. Тогда вы можете решить свои проблемы в комментариях, как показано ниже.

const Foo& getFoo() const { return *foo_ptr; }

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