Указатель на константный объект как член данных

В соответствии с рекомендациями C++ по IsoCpp у нас не должно быть const или ссылочного члена данных: C.12: Не делайте элементы данных постоянными или ссылками

Но он не указывает, разрешен ли указатель на объект const или нет. Рассмотрим пример:

class Connection {
    gsl::not_null<const Network*> m_network;
    ...

public:
    [[nodiscard]] const Network* getNetwork() const;
    ...
}

// Implementation
const Network* Connection::getNetwork() const {
    return m_network;
}

Соответствует ли он описанным передовым методам? Указатель не const, а данные, на которые указывает указатель.

Должны ли мы удалить const из объявления члена, но по-прежнему помечать возвращаемый тип геттера как указатель на const?

Совершенно нормально. Сам указатель не является константой. Он может безопасно указывать на константу. Если член является константным, конструктор присваивания отключен, и вам придется написать свой собственный. В вашем случае этого не происходит.

doug 06.05.2022 03:28

Есть веские причины сделать член константным. Необычные, но они есть

Joe 06.05.2022 03:41

Есть также хорошее использование для ссылочных членов. И есть много классов, которые не должны назначаться. Масса причин сделать прямо противоположное заявленному. В конце концов, это конкретное руководство настолько слабое, что я бы не принял его в качестве руководства по кодированию.

Sebastian 06.05.2022 05:16
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
3
85
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Да, ты можешь

Если у вас есть константный член данных, конструктор копирования и перемещения удаляется. Но это применимо только в том случае, если сам указатель является константой, а не указанным значением.

const & или const * подходят только тогда, когда класс не копируется (например, какой-то «класс менеджера»)

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

Это зависит.

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

Итак, подумайте об этом:

struct Connection {
  Network const& network;
  /**/
};

Копировать это совершенно нормально, верно? Но тогда назначать перерывы, потому что network нельзя будет пересадить.

Итак, в этом случае, заменив этот член, например. std::shared_ptr<Network const> в порядке. Предположительно несколько подключений могут использовать одну и ту же сеть.

Но если вы не хотите совместного использования, но каждый объект должен иметь свою собственную копию члена, тогда вам остается реконструировать этот член при назначении, потому что старый объект не может быть изменен. В зависимости от объекта это может быть не то, что вы хотите сделать.

Например:

struct Connection {
  std::shared_ptr<Network const> network;
  std::unique_ptr<std::vector<Entry> const> properties;
};

Помимо того, что указатель на вектор является плохой формой (двойная косвенность без уважительной причины). Реконструкция вектора заново требует нового выделения памяти, в то время как простое повторное использование старого не будет (при условии, что выделено достаточно памяти).

Конечно, это немного сконструированный пример, и, возможно, есть способ обойти это. Но дело в том, что что сходство вашей копии и назначения будет сильно зависеть от качества копии и назначения объекта-члена.

В таком случае те же рассуждения, которые применялись к ситуации без указателя, точно так же применимы и к ситуации с указателем. Вам придется решить, приемлемо ли это для вашего типа.


Однако я считаю, что не каждый тип должен можно присваивать. Вы можете принять сознательное решение иметь тип, который просто не может быть назначен. Тогда и только тогда просто используйте константный член без какой-либо косвенности.

Спасибо за поучительный ответ. Вы правы в отношении соединения и сети, в моем случае сеть является константой в данном соединении. Я не хочу, чтобы Connection мог что-либо изменить в сети, поэтому я не использовал std::shared_ptr, чтобы сохранить право собственности только в сети. С этой информацией использование const Network* все еще применимо, верно? Что касается комментария к ссылкам, я использовал его, но это вызвало у меня проблемы со временем жизни объекта, поэтому я изменил Networks на кучу. Еще раз спасибо!

Vinícius Ferrão 06.05.2022 18:14

Для пожизненных выпусков также есть вариант std::optional<Network>

Sebastian 06.05.2022 19:55

Я не уверен, что std::optional имеет смысл, поскольку данное соединение не существует без сети, поэтому это необязательно. Проблема с продолжительностью жизни, с которой я столкнулся, заключается в том, что объект сети создается внутри другого объекта, и после уничтожения этого объекта ссылка теряется. Теперь это просто std::move Сеть туда, где она должна быть, и мы ее не потеряли.

Vinícius Ferrão 06.05.2022 20:23

Будет ли в этом случае std::unique_ptr<const Network> лучшим выбором, чем const Network*?

Sebastian 06.05.2022 21:26

Да, я согласен, описанный вами сценарий звучит как уникальный или общий указатель. В зависимости от того, собираетесь ли вы сохранить более одного подключения для данного сетевого объекта. Как я уже сказал в ответе, я не вижу проблем с общим указателем, содержащим константный объект. В любом случае, я бы посоветовал не таскать необработанные указатели.

bitmask 06.05.2022 22:18

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