Почему необработанный указатель и интеллектуальный указатель unique_ptr, указывающие на один и тот же ресурс, не вызывают никаких проблем? (С++)

Я знаю, что unique_ptr делает интеллектуальный указатель владельцем ресурса и, следовательно, не позволяет нескольким указателям указывать на один и тот же ресурс.

Но почему тогда можно создать необработанный указатель на этот умный указатель с помощью .get(), а затем передать его функции? В конце у вас есть два указателя, которые владеют ресурсом и имеют возможность изменять его значение? Это нарушит правило unique_ptr smart ptr, владеющего исключительно ресурсом.

В примере ниже я создал простую программу, которая изменяет значение, на которое указывает указатель smrt smrtPtr.

Бывший:

#include <iostream>
#include <memory>
#include <utility> //move semantics

void changeValue(int* ptr)
{
    if (!ptr)       //check if pointer is null
        return;
    *ptr = 17;       //change value to 17
}



int main()
{

    auto smrtPtr{ std::make_unique<int>(5) };
 
    changeValue(smrtPtr.get());    //creates a raw pointer of smrtPtr

    if (smrtPtr)            //if it does contain resource
        std::cout << *smrtPtr;

        return 0;
}

Большое спасибо

Необработанные указатели не подразумевают НИКАКОГО владения. В этом их красота и их проклятие.

user4581301 07.05.2024 00:57

Важное чтение: Что такое владение ресурсами или указателями?

user4581301 07.05.2024 01:01

большое спасибо, но, например, интеллектуальный указатель std::weak_ptr также не владеет ресурсом, но ему не разрешено использовать один и тот же ресурс с одним интеллектуальным указателем std::unique_ptr?

tadm123 07.05.2024 01:02

Чтобы получить указатель из weak_ptr, вам нужно получить shared_ptr из weak_ptr, если можете, а затем получить указатель из shared_ptr. Если вы взяли этот указатель, а затем поместили его в unique_ptr, у вас теперь есть конфликтующие владельцы: unique_ptr освободит ресурс, когда он выйдет за пределы области действия, а последний shared_ptr также освободит ресурс. В лучшем случае программа терпит двойную бесплатность, но вам не повезет, если вы зайдете так далеко. Необработанный указатель освобождает ресурс только тогда, когда вы явно вызываете к нему delete.

user4581301 07.05.2024 01:08

@ tadm123 weak_ptr не имеет смысла, поскольку участвует в семантике владения. Способ подключения к нему — это блок управления, который создается при создании shared_ptr. Поскольку ничто другое не должно владеть unique_ptr, на 100% можно вернуть необработанный указатель в качестве дескриптора.

NathanOliver 07.05.2024 01:09

Обратите внимание: если вы получаете shared_ptr от weak_ptr, этот shared_ptr является таким же владельцем, как и любые другие связанные shared_ptr. Причина этого в том, чтобы убедиться, что пока вы удерживаете shared_ptr, полученный от weak_ptr, существует хотя бы один экземпляр shared_ptr, поддерживающий работоспособность принадлежащего ресурсу. Никто другой не сможет высвободить его из-под вас, если только он не сделает что-нибудь действительно <ругательство удалено> глупо, например, вручную delete это.

user4581301 07.05.2024 01:13

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

user4581301 07.05.2024 01:20

«и, следовательно, он не позволяет нескольким указателям указывать на один и тот же ресурс». он не делает ничего подобного. Это означает, что интеллектуальный указатель является единственным ВЛАДЕЛЬЦЕМ ресурса и, следовательно, несет исключительную ответственность за определение момента его удаления. Это не имеет никакого отношения к тому, кто может просматривать содержимое.

xaxxon 07.05.2024 01:45

@ tadm123 «умный указатель std::weak_ptr также не владеет ресурсом» — это достаточно верно; weak_ptr своего рода арендует ресурс вместо того, чтобы владеть им. У него есть соглашение, которое дает ему доступ к ресурсу до тех пор, пока ресурс существует. Однако именно владельцы, а не арендаторы, решают, когда ресурс будет отчужден. Если ресурс пропал и арендатор хочет его получить, ему говорят: «Плохо». Обратите внимание, что по замыслу unique_ptr не сдают свои ресурсы в аренду таким образом.

JaMiT 07.05.2024 02:28

@ tadm123 tadm123 многие вещи, которые вы говорите «не разрешены», следует называть «неправильными», но это не значит, что плохая программа не может этого сделать.

xaxxon 07.05.2024 03:41

Обычно есть два фактора, которые заставляют людей спотыкаться при использовании «умных указателей»; 1) они думают о них как об указателях, а не как об объектах с конкретными правилами владения, и 2) они никогда по-настоящему не задумывались о природе владения. (Подумайте, у скольких вещей вокруг вас есть конкретный владелец, а не вы, и тем не менее вы можете их просматривать и даже использовать.)

molbdnilo 07.05.2024 09:31

с возможностью изменения своего значения" Это константность, не связанная с принадлежностью.

Jarod42 07.05.2024 13:36
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
12
101
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Весь ваш вопрос основан на путанице в том, что делает умный указатель:

«и, следовательно, он не позволяет нескольким указателям указывать на один и тот же ресурс».

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

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

Уникальный указатель означает, что за удаление отвечает только он. Общий указатель означает, что за удаление отвечает последний общий указатель.

Ничто из этого не влияет на возможность доступа к ресурсу.

Стандартная терминология — «право собственности», но я понимаю, что это несколько неточно. В реальном мире часто бывает так, что владелец чего-либо — единственный, кто может это что-то изменить. (Например, большинство домовладельцев были бы расстроены, если бы кто-то пришел и покрасил их дом в новый цвет.) Это не то, что означает «владение» в отношении управления памятью.

Более точным термином могло бы быть «хранитель». Работа хранителя – заботиться о чем-то. Здесь не подразумевается, что «что-то» принадлежит исключительно хранителю, а лишь то, что хранителю приходится следить за тем, чтобы о вещах заботились, например, убираться в конце дня. Это возвращает нас к управлению памятью. «Хранитель» (обычно называемый «владельцем») отвечает за очистку памяти. Время уборки зависит от хранителя, с одной оговоркой. Если существует более одного хранителя (подумайте shared_ptr), существует соглашение, что очистка ложится на последнего вышедшего хранителя. (Хранитель 1: «Я направляюсь домой. Ты запираешься, да?» Хранитель 2: «Да, я этим занимаюсь».)

Когда указатель получается из интеллектуального указателя через get(), этот указатель обеспечивает доступ к хранимому объекту. С этим доступом можно разрешить модифицировать, но не уничтожать, объект. Аналогично, доступ в конференц-зал часто включает в себя разрешение переставлять, но не повреждать, стулья. А может быть, повесить плакаты или другие наглядные пособия. Дело в том, что изменения могут быть внесены. После собрания участники уходят, а хранитель запирается, закрывая весь разрешенный доступ. Это роль интеллектуального указателя — блокировать/завершать разрешенный доступ, когда вокруг больше нет хранителя.

(Причина получения статуса «разрешено» объясняется историей отеля. В конференц-зале можно запереться и получить запрет на доступ. Если окружающая среда не решит снести это место в одночасье.)


Однако уже поздно менять терминологию. Мы застряли на слове «владелец», но если мысль «хранитель» помогает, действуйте.

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