Учитывая этот код:
class Clazz {
private:
std::shared_ptr<int> something;
public:
Clazz() : something(std::make_shared<int>(0)) {}
int &getSomething() {
return *something;
}
}
Это приводит к висячим ссылкам, поскольку полученная ссылка в какой-то момент может указывать на освобожденную память. Мне это кажется зеркалом сценария с висячим указателем, но мне не удалось найти никаких источников по этому поводу.
Давайте не будем делать никаких предположений о сроке службы объекта Clazz.
В стандартной библиотеке есть много случаев, когда возвращается ссылка на память, принадлежащую классу. Например, std::vector::operator[], а также std::shared_ptr::operator*, который вы здесь использовали.
Если объект Clazz умирает, ссылка действительно может висеть (но, поскольку это shared_ptr, могут быть другие общие владельцы, поддерживающие something живым).
Суть в том, что ссылка действительна до тех пор, пока жив объект, управляемый shared_ptr.
Если мы не должны делать никаких предположений о времени жизни clazz, то никакая ссылка, зависящая от его времени жизни, никогда не должна возвращаться. Неважно, «управляемая память» это или нет. На самом деле мы всегда делаем такие предположения. Здоровое эмпирическое правило гласит: если вы получаете ссылку из метода экземпляра, предполагайте, что она будет оставаться действительной ровно до тех пор, пока экземпляр, из которого вы ее получили. Если ваш класс ведет себя соответствующим образом, то все в порядке.
У Rust есть время жизни в этом типе, а у C++ — нет.
@tjzel Время жизни указанного int частично зависит от времени жизни связанного Clazz экземпляра. Если мы не можем делать никаких предположений о времени жизни объекта Clazz и не располагаем дополнительной информацией о других экземплярах Shared_ptr для этого int, то мы не сможем ничего ответить о достоверности ссылки.
Если вы используете std::shared_ptr, передайте его по значению. В этом весь смысл. Возвращайтесь по ссылке только в том случае, если вы можете гарантировать, что рассматриваемый объект не исчезнет из-под вас.





Опять же, в отношении подобных вещей существует множество «зависимостей» и личных предпочтений.
Время жизни «необработанных» указателей всегда должно быть явным.
Все просто, если у вас есть умный указатель и вы предоставляете своим внутренним функциям необработанные указатели (или ссылки) — вам просто нужно помнить, что эти указатели нигде не следует хранить. А поскольку вы держите умный указатель, все функции, которые вы вызываете с помощью необработанного указателя, не будут иметь проблем.
Все немного сложнее, когда вы возвращаете такие указатели из API. Даже если это мой собственный API, я предпочитаю документировать его соответствующим образом, например
/* ...
* has<T> returns a pointer to the stored item, or nullptr. This
* pointer is valid until a yield.
*/
чтобы напомнить людям и/или себе, что нельзя держать этот указатель под рукой.
В других случаях я мог бы возвращать указатели на внутренние буферы, сообщая людям, что данные не изменятся до следующего вызова.
Я не всегда все записываю. Например, если я возвращаю указатель на внутренний буфер, я обычно не упоминаю, что этот указатель станет недействительным при уничтожении объекта. Обычно я предполагаю некоторый уровень знаний пользователей и документирую только то, что не сразу очевидно.
Также обратите внимание, что в моей книге необработанные указатели имеют допустимую силу, но не имеют связанной с ними функции free. Они просто становятся недействительными в определенный момент времени, но пользователям никогда не придется их освобождать — я всегда возвращаю что-то более продвинутое, если такие вещи нужно очистить.
Ссылка не висит, пока объект
Clazzжив (иsomethingне сброшен). Таким образом, могут быть сценарии, в которых это действительно. Почему вы хотите это сделать, это другой вопрос. Вы не предоставили нам достаточно контекста, чтобы давать советы.