После того, как вы приняли интеллектуальные указатели boost, можно ли использовать необработанные указатели?

Мне любопытно, поскольку я начинаю принимать больше идиом повышения и того, что кажется передовым опытом. Интересно, в какой момент мой С ++ хоть отдаленно похож на С ++ прошлых лет, часто встречающийся в типичных примерах и в умах тех, кто Еще не знакомы с "Современным C++"?

Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
12
0
1 725
10
Перейти к ответу Данный вопрос помечен как решенный

Ответы 10

В наши дни я практически отказался от использования необработанных указателей. Я даже начал просматривать нашу базу кода в поисках мест, где использовались необработанные указатели, и переключил их на вариант с интеллектуальным указателем. Удивительно, сколько кода мне удалось удалить, выполнив это простое действие. На управление временем жизни необработанных указателей C++ тратится так много кода.

Единственные места, где я не использую указатели, - это пара сценариев взаимодействия с другими базами кода, которые я не контролирую.

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

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

О, и есть еще одно место, где можно использовать необработанные указатели:

boost::shared_ptr<int> ptr(new int);

Я думал, что у классов boost: pointer нет накладных расходов? Неужели компилятор все не оптимизирует?

ApplePieIsGood 12.12.2008 21:53

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

coppro 12.12.2008 22:17

Не могу вспомнить ни единого случая за 15 лет программирования на C++, который мне когда-либо требовался для явного выделения одного int в куче. Другое дело - массив int: s, но тогда всегда есть std :: vector <int>.

Andreas Magnusson 21.12.2008 03:27

Если у вас есть круговые структуры данных, например, A указывает на B, а B указывает обратно на A, вы не можете наивно использовать интеллектуальные указатели как для A, так и для B, поскольку тогда объекты будут освобождены только от дополнительной работы. Чтобы освободить память, вам нужно вручную очистить интеллектуальные указатели, что примерно так же плохо, как удаление, от которого избавляются интеллектуальные указатели.

Вы можете подумать, что это происходит не очень часто, но предположим, что у вас есть родительский объект, который имеет интеллектуальные указатели на группу дочерних объектов. Где-то по пути кому-то нужно найти Родителя для Дочернего, поэтому они добавляют элемент интеллектуального указателя в Дочерний, который указывает обратно на родителя. Молча память больше не освобождается.

Требуется некоторая осторожность. Умные указатели не эквивалентны сборке мусора.

Для этого нужен boost :: weak_ptr, если он у вас есть. Таким образом, вы все равно можете использовать интеллектуальные указатели, а не необработанные, просто не все интеллектуальные указатели будут shared_ptr.

Steve Jessop 12.12.2008 21:13

Абсолютно boost :: weak_ptr - это еще один способ решить проблемы с круговой ссылкой, но я думаю, что моя точка зрения все еще остается в силе: вы должны обращать внимание, а не просто слепо использовать любые умные указатели, которые у вас есть.

David Norman 12.12.2008 21:49

Полагаю, я предполагаю, что когда спрашивающий говорит «принятые интеллектуальные указатели boost», он имеет в виду их все, используемые надлежащим образом, а не только shared_ptr, используемый для всего. Вы правы, что не все читатели это оценят :-)

Steve Jessop 13.12.2008 05:27

Я почти не использую shared_ptr, потому что вообще избегаю совместного владения. Поэтому я использую что-то вроде boost::scoped_ptr, чтобы «владеть» объектом, но все другие ссылки на него будут необработанными указателями. Пример:

boost::scoped_ptr<SomeType> my_object(new SomeType);
some_function(my_object.get());

Но some_function будет иметь дело с необработанным указателем:

void some_function(SomeType* some_obj)
{
  assert (some_obj);
  some_obj->whatever();
}

Обидите меня - я собирался сказать, что передача по необработанному указателю может использоваться по соглашению, чтобы подразумевать, что вызываемый объект не будет сохранять ссылку на объект (или, по крайней мере, не таким образом, который влияет на управление ресурсами).

Steve Jessop 12.12.2008 21:09

Как сохранить ссылку на объект таким образом, чтобы это не повлияло на управление ресурсами? Как только ресурс уничтожен, хранитель этой ссылки должен теперь знать об этом факте, верно?

ApplePieIsGood 12.12.2008 21:52

Все дело в объемах. Поместите владельца в крайнюю область видимости, в которой будет использоваться объект, а затем просто передайте ему указатели в этой области. Никакая ссылка не может существовать в более широкой области, чем владелец, и, таким образом, она гарантированно указывает на действительный объект.

Nemanja Trifunovic 12.12.2008 22:24

Почему бы вам не передать scoped_ptr по ссылке?

Patrick 12.12.2008 23:11

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

Nemanja Trifunovic 13.12.2008 04:20

@Patrick: я думаю, что передача scoped_ptr может быть немного неудобной по сравнению с необработанным указателем. Если позже вы захотите провести рефакторинг, чтобы переданная вещь была const, тогда изменение будет с scoped_ptr <T> на scoped_ptr <const T>, а не с T * на const T *. Это не одна из сильных сторон шаблонов C++.

Steve Jessop 13.12.2008 05:51

Ссылайтесь на людей! Если вы не хотите явно разрешить вызов функции с nullptr, я бы сказал, что ссылки - это путь. Зачем обнаруживать ошибку во время выполнения, если компилятор с радостью сделает это за вас?

Andreas Magnusson 21.12.2008 03:23

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

Я считаю, что основное различие между «современным» C++ и старым * состоит в осторожном использовании инвариантов классов и инкапсуляции. Хорошо организованный код, естественно, имеет меньше летающих указателей. Я почти так же нервничаю плавать в shared_ptrs, как если бы я был в новостях и удалял.

Я с нетерпением жду unique_ptr на C++ 0x. Я думаю, что это уберет несколько (умных) указателей, которые все еще бродят по дикой природе.

* все еще, к сожалению, очень часто

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

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

Я пишу C++, который должен сосуществовать с Objective C (используя Objective C++ для моста). Поскольку объекты C++, объявленные как часть классов Objective C++, не имеют вызываемых конструкторов или деструкторов, вы не можете удерживать их там в интеллектуальных указателях.

Поэтому я предпочитаю использовать необработанные указатели, хотя часто с boost :: intrustive_ptr и внутренним счетчиком ссылок.

Это правильно? В моем чтении документа говорится, что вызывается конструктор без аргументов, а деструктор вызывается при уничтожении объекта Objective C. Возможно, что-то изменилось / улучшилось с тех пор, как вы опубликовали.

Alan Kent 21.01.2011 15:09

Вещи изменились / улучшились с тех пор, как я опубликовал :-) На самом деле, с тех пор, как я опубликовал - я уже немного устарел.

philsquared 25.01.2011 20:34

Не то чтобы я бы это сделал, но вам нужны необработанные указатели, чтобы реализовать, скажем, связанный список или график. Но гораздо разумнее было бы использовать std::list<> или boost::graph<>.

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

Всего несколько штук в голове:

  • Перемещение по файлам с отображением памяти.
  • Вызовы Windows API, в которых необходимо выделить избыточное количество ресурсов (например, LPBITMAPINFOHEADER).
  • Любой код, в котором вы возитесь с произвольной памятью (VirtualQuery () и т.п.).
  • Практически каждый раз, когда вы используете reinterpret_cast <> для указателя.
  • Каждый раз, когда вы используете place-new.

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

Всякий раз, когда мне нужно выделить память (скажем, чтобы сохранить BITMAPINFOHEADER с дополнительными байтами в конце), я бы использовал std :: vector, если это возможно, тогда не о чем беспокоиться, и если Windows API сообщит мне мою выделенную память недостаточно, std :: vector :: resize () сладко.

Andreas Magnusson 21.12.2008 03:19

Конечно. Вы по-прежнему можете использовать стандартные контейнеры или интеллектуальные указатели для управления базовой памятью, когда это возможно. Дело в том, что когда вы собираетесь поговорить с Windows API, вы собираетесь привести его к необработанному указателю, о чем и был задан исходный вопрос.

Tim Lesher 24.12.2008 00:13

Также для взаимодействия с «внешним миром». Если ваш пользователь запрашивает буфер, он получает буфер, а не умный указатель.

Edouard A. 04.02.2009 19:37

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