В соответствии с рекомендациями 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
?
Есть веские причины сделать член константным. Необычные, но они есть
Есть также хорошее использование для ссылочных членов. И есть много классов, которые не должны назначаться. Масса причин сделать прямо противоположное заявленному. В конце концов, это конкретное руководство настолько слабое, что я бы не принял его в качестве руководства по кодированию.
Да, ты можешь
Если у вас есть константный член данных, конструктор копирования и перемещения удаляется. Но это применимо только в том случае, если сам указатель является константой, а не указанным значением.
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 на кучу. Еще раз спасибо!
Для пожизненных выпусков также есть вариант std::optional<Network>
Я не уверен, что std::optional
имеет смысл, поскольку данное соединение не существует без сети, поэтому это необязательно. Проблема с продолжительностью жизни, с которой я столкнулся, заключается в том, что объект сети создается внутри другого объекта, и после уничтожения этого объекта ссылка теряется. Теперь это просто std::move
Сеть туда, где она должна быть, и мы ее не потеряли.
Будет ли в этом случае std::unique_ptr<const Network>
лучшим выбором, чем const Network*
?
Да, я согласен, описанный вами сценарий звучит как уникальный или общий указатель. В зависимости от того, собираетесь ли вы сохранить более одного подключения для данного сетевого объекта. Как я уже сказал в ответе, я не вижу проблем с общим указателем, содержащим константный объект. В любом случае, я бы посоветовал не таскать необработанные указатели.
Совершенно нормально. Сам указатель не является константой. Он может безопасно указывать на константу. Если член является константным, конструктор присваивания отключен, и вам придется написать свой собственный. В вашем случае этого не происходит.