Умные указатели нельзя использовать как необработанные указатели автоматически?

Я пытаюсь преобразовать коды для использования интеллектуальных указателей вместо необработанных указателей. Но было интересно - действительно ли умные указатели нельзя использовать в качестве необработанных указателей?

В этом примере:

#include <iostream>
#include <string>
#include <memory>

void printer(int* x)
{
    std::cout << "x = " << x << std::endl;
}

int main()
{   
    auto x = std::make_unique<int>(5);
    printer(x);
    return 0;
}

Я получаю сообщение об ошибке:

In function 'int main()': 14:14: error: cannot convert
'std::unique_ptr<int, std::default_delete<int> >' to 'int*' for argument '1'
to 'void printer(int*)' 

Как это должно быть закодировано? Спасибо!

Вам нужно printer(x.get());, чтобы получить доступ к необработанному указателю позади. Это не делается автоматически по уважительным причинам.

πάντα ῥεῖ 30.05.2019 10:34

См. Херб Саттер по этому поводу.

Michael Doubez 30.05.2019 18:16

@ πάνταῥεῖ Это не делается неявно по крайне субъективным причинам: «сырые» ptr «небезопасны». Нет никакой внутренней проблемы в том, чтобы разрешить их. И сказать, что слишком опасно разрешать преобразование в ptr, когда вы продолжаете использовать ptr, в корне противоречит.

curiousguy 04.06.2019 19:05

@MichaelDoubez "если бы неявное преобразование в * было разрешено, компилировалось бы молча -- urk" Сказать, что неявные преобразования позволяют компилировать больше программ, тривиально верно, и это вовсе не убедительный аргумент.

curiousguy 04.06.2019 19:06

@curiousguy Умные указатели связаны с семантикой владения, и обернутый указатель в этом отношении является гражданином второго сорта. Лучшее, что вы можете ожидать вместо get(), это неявное преобразование в std::weak_ptr<T>.

πάντα ῥεῖ 04.06.2019 19:10

@πάνταῥεῖ Весь смысл использования смарт-указательного указателя заключается в том, чтобы получить доступ к его «гражданину второго сорта», лол.

curiousguy 04.06.2019 19:16

@curiousguy Вы пропустили "... контролируемым образом" ;)

πάντα ῥεῖ 04.06.2019 19:17

Неявное преобразование @curiousguy является корнем многих болезненных ошибок. Любая передача права собственности никогда не должна быть неявной, и передача указателя может быть передачей права собственности. Учитывая эту точку зрения и тот факт, что код пишется только один раз, добавленные 6 символов — это небольшие затраты.

Michael Doubez 05.06.2019 00:11

@MichaelDoubez 6 символов .get() также не передают право собственности. По моему опыту, неявные преобразования — это нормально.

curiousguy 05.06.2019 01:05

@curiousguy цель именно в этом: вы не должны передавать это неявно. Всякий раз, когда мне приходится набирать .get(), я знаю, что должен быть осторожен. По моему опыту, неявные преобразования редки и используются только тогда, когда это действительно необходимо (например, с утиным типом), а не для синтаксического сахара. Когда даже сделать конструктор с одним параметром явным, чтобы избежать создания экземпляра объекта по ошибке. Без этого анализ воздействия был бы намного сложнее.

Michael Doubez 05.06.2019 10:59

@MichaelDoubez "неявные преобразования редки" Вы имеете в виду, что определяемые пользователем неявные преобразования редки, не так ли?

curiousguy 06.06.2019 01:40

@curiousguy да, я имею в виду пользовательские конверсии. К счастью, компиляторы имеют хорошую поддержку предупреждений об опасных преобразованиях в языке (или поддержку рискованных преобразований, таких как конструктор std::string, принимающий логический параметр).

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

Ответы 2

std::make_unique<>() возвращает std::unique_ptr, что делает переменную x типа std::unique_ptr<int>. Эти интеллектуальные указатели — это не просто необработанные указатели, и вы не можете использовать их так же, как необработанные указатели. Вместо этого вы должны использовать метод get() для x, чтобы получить int*, на который он указывает.

Это было бы аргументом даже против неявного преобразования в языке.

curiousguy 04.06.2019 19:07
Ответ принят как подходящий

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

void kill(int *p) { delete p; }

Молча делать конвертацию при звонке kill(p); было бы неправильно! Это приведет к двойному удалению. У указателя нет способа узнать, что он должен перестать владеть объектом, об этом нужно сообщить через вызов release. Все остальное было бы неправильно.

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

Очевидно, что передача права собственности должна быть явной (за исключением перемещения копии из rvalue).

curiousguy 04.06.2019 18:47

Вы должны упомянуть get() и release() для стандартных типов указателей.

Sebastian Redl 04.06.2019 18:51

@curiousguy Это была опечатка, я имел в виду get()

Sebastian Redl 04.06.2019 18:53

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