shared_ptr<int> ptr = make_shared<int>(10);
int& val = *ptr;
ptr = make_shared<int>(20);
// val now points to freed memory
В приведенном выше коде я могу читать и записывать в val, который указывает на освобожденную память. Та же проблема возникает, если мы используем .get () в shared_ptr. Таким образом, можно прострелить себе ногу, даже если прибегнуть к умным указателям.
Очевидно, что никто не будет кодировать так, как указано выше. Один из способов добиться этого - если у нас будет что-то вроде этого -
class Foo {
public:
int& getVal() { return *p; }
private:
shared_ptr<int> p;
};
Кто-то может вызвать getVal (), после чего другой член вышеуказанного класса может перезаписать p другим значением. Если getVal () выше возвращает shared_ptr вместо ссылки, мы не увидим этой проблемы. Некоторые могут возразить, что возврат shared_ptr дороже, чем возврат ссылки, поскольку нам нужно увеличить счетчик в блоке управления shared_ptr.
Итак, следует ли руководствоваться тем, чтобы не возвращать ссылку на shared_ptr, как указано выше?
В С ++ все опасно при неправильном использовании ...
И действительно, проблема в висящих отсылках. Это не имеет ничего общего с shared_ptr как таковым.
C++ - это не язык для няни. Вам дают много веревки, чтобы прострелить себе ногу. И const - ваш друг.





Опасность здесь не в operator*, а в хранении ссылок.
Сохранение ссылок на что-нибудь означает, что вы несете личную ответственность за срок службы объекта, о котором говорите.
int getVal() { return *p; }
это самое безопасное и простое решение. C++ обожает ценности.
У вас есть более сложный объект, копирование которого стоит дорого? Тогда будьте внимательнее.
gsl::span<int const> getVals() { return {p->data(), p->size()}; }
здесь у нас есть что-то, что является ссылкой концептуально, несмотря на то, что она не относится к типу ссылки или указателя.
Потребители должны знать правило срока службы того, что возвращает getVals. Если они хотят сохранить это, они несут ответственность за копирование данных.
Только в крайних случаях следует учитывать:
std::shared_ptr<gsl::span<int const>> getVals() {
return p?make_shared_span<int const>( p, {p->data(), p->size()} ):nullptr;
}
где make_shared_span создает общий вид диапазона в общий ptr.
Особенно страшно делиться ссылками на изменяемые данные. Вы никогда не знаете, изменятся ли данные у вас под ногами, из-за чего состояние любого кода, работающего с ними, запутывается с состоянием всего кода, который также имеет на него ссылку.
Один из способов обойти проблемы «совместного использования ссылок» и времени жизни в базах кода C++ - это работа с неизменяемыми данными.
shared_ptr<gsl::span<int const>const> с на самом деле неизменный - гораздо более разумная вещь для работы, чем shared_ptr<gsl::span<int>>.
Вы увидите это в проектах, таких как здесь или при поддержке документа с помощью неизменный магазин libgit.
«Решение» этой проблемы путем передачи общих указателей на данные повсюду приведет к тому, что объекты будут жить намного дольше, чем следовало бы, поскольку люди хранят некоторый общий указатель на них, никогда не намереваясь использовать его снова.
Обратите внимание на срок службы, и вы получите прекрасные результаты RAII.
Бывают ситуации, когда совместное использование общего указателя имеет смысл, и это когда вы на самом деле хочу совместное владение, а не когда «я не хочу думать о времени жизни». Совместное владение - это более сложный вид жизни, потому что в некоторых ситуациях вам не нужно думать о результатах жизни в спагетти на всю жизнь.
Хранить ссылки опасно. Можем ли мы просто вытатуировать это на внутренней стороне век программистов на C++?
Вы также можете вернуть
std::weak_ptr