Объясните, как алиасинг-конструктор std::shared_ptr позволяет владеть объектом, указывая на его подобъект.
Алиасинг-конструктор создаёт std::shared_ptr, который хранит указатель на подобъект, но разделяет владение с другим std::shared_ptr, управляющим целым объектом. Поэтому подобъект остаётся доступным, пока существует хотя бы один алиасный указатель, а уничтожение ресурса выполняется владельцем из исходного управляющего блока.
Ручное управление памятью разделяет две задачи: определить, какой адрес использовать, и обеспечить время жизни объекта. На практике эти понятия часто не совпадают: пользователю нужен указатель на поле или элемент, но уничтожать нужно содержащий объект.
std::shared_ptr, стандартизированный в C++11, решает эту задачу через управляющий блок. Алиасинг позволяет сохранить единый контроль над временем жизни объекта, не создавая отдельное владение для его подобъекта.
Предположим, объект содержит ресурс или важное состояние, а функция должна получить доступ только к одному его полю. Если передать обычный указатель на поле, вызывающий код обязан отдельно гарантировать, что содержащий объект ещё жив.
Если ошибочно создать новый std::shared_ptr непосредственно из адреса поля, указатель не будет корректно владеть содержащим объектом. Это может привести к двойному освобождению, обращению к уничтоженному объекту или попытке вызвать delete для памяти, которая не была выделена отдельно.
У std::shared_ptr есть две логически разные части: управляющий блок с информацией о владельцах и хранимый указатель, возвращаемый через get() и используемый оператором ->. Алиасинг-конструктор оставляет управляющий блок от исходного указателя, но записывает в новый объект адрес подобъекта.
После session.reset() объект Session не уничтожается: алиасный connection продолжает владеть тем же управляющим блоком. Когда уничтожается последний такой std::shared_ptr, управляющий блок применяет удалитель исходного владельца и уничтожает Session, а не отдельно Connection.
Это не копирование объекта и не создание независимого владельца подобъекта. Алиасный указатель должен использоваться только пока хранимый адрес остаётся корректным относительно времени жизни объекта-владельца; особенно опасно сохранять его после ручного разрушения подобъекта или при нарушении инвариантов содержащего объекта.
Алиасинг добавляет стоимость shared_ptr: подсчёт ссылок, управляющий блок и обычно динамическое выделение памяти. Если владение не требуется, предпочтительнее обычная ссылка или невладеющий указатель с явно гарантированным временем жизни.
Сервис хранит подключение внутри объекта сессии, а подсистеме отправки сообщений нужно передать только подключение. Вариант с сырым указателем прост и почти не создаёт накладных расходов, но требует внешней гарантии, что сессия не будет уничтожена раньше подсистемы.
Передача копии подключения может быть невозможна или нежелательна: копирование может быть запрещено, дорого или семантически неверно. Создание отдельного std::shared_ptr<Connection> из адреса поля некорректно, поскольку такой указатель не знает, что поле является частью Session.
Выбран алиасный std::shared_ptr<Connection> на основе std::shared_ptr<Session>. Он сохраняет сессию живой на время работы подсистемы, не создаёт ложного отдельного владения подключением и корректно уничтожает составной объект целиком. Компромисс — накладные расходы совместного владения и необходимость не путать алиасинг с независимым выделением объекта.
std::shared_ptr счётчик владельцев?Да. Алиасный указатель разделяет управляющий блок с исходным std::shared_ptr, поэтому его создание обычно увеличивает число сильных владельцев. Уничтожение исходного указателя не завершает время жизни объекта, пока остаётся алиасный владелец.
Уничтожается объект и применяется удалитель, связанные с исходным управляющим блоком. Адрес, хранимый алиасным указателем, не удаляется отдельно; это принципиально важно для поля, элемента массива или другого подобъекта, который не был выделен самостоятельным вызовом new.
Можно, но только пока адрес элемента остаётся действительным. Например, изменение размера std::vector может переместить его элементы и сделать сохранённый адрес недействительным, хотя std::shared_ptr продолжит поддерживать время жизни самого контейнера. Алиасинг гарантирует жизнь владельца, но не отменяет правил инвалидирования указателей конкретного контейнера.