Я прочитал в нескольких статьях, что сырые указатели почти никогда не должны использоваться. Вместо этого они всегда должны быть заключены в интеллектуальные указатели, будь то область видимости или общие указатели.
Однако я заметил, что фреймворки, такие как Qt, wxWidgets и библиотеки, такие как Boost, никогда не возвращают и не ожидают интеллектуальных указателей, как если бы они вообще не использовали их. Вместо этого они возвращаются или ожидают сырых указателей. Есть ли причина для этого? Должен ли я держаться подальше от умных указателей при написании общедоступного API и почему?
Просто интересно, почему умные указатели рекомендуются, когда многие крупные проекты, кажется, избегают их.
c++
api
pointers
smart-pointers
Laurent
источник
источник
unique_ptr
? Никак нет. Предназначены ли Qt / WxWidgets для встроенных систем или систем реального времени? Нет, они предназначены для Windows / Mac / Unix на рабочем столе - максимум. Умные указатели предназначены для программистов, которые хотят, чтобы это было правильно.Ответы:
Помимо того, что многие библиотеки были написаны до появления стандартных интеллектуальных указателей, основной причиной, вероятно, является отсутствие стандартного двоичного интерфейса приложений C ++ (ABI).
Если вы пишете библиотеку только для заголовков, вы можете передать разумные указатели и стандартные контейнеры. Их источник доступен вашей библиотеке во время компиляции, поэтому вы полагаетесь только на стабильность их интерфейсов, а не на их реализации.
Но из-за отсутствия стандартного ABI вы, как правило, не можете безопасно передавать эти объекты через границы модулей. GCC
shared_ptr
, вероятно, отличается от MSVCshared_ptr
, который также может отличаться от Intelshared_ptr
. Даже с одним и тем же компилятором эти классы не гарантированно двоично совместимы между версиями.Суть в том, что если вы хотите распространять предварительно собранную версию вашей библиотеки, вам нужен стандартный ABI, на который можно положиться. У C его нет, но поставщики компиляторов очень хорошо разбираются во взаимодействии между библиотеками C для данной платформы - существуют стандарты де-факто.
Ситуация не так хороша для C ++. Отдельные компиляторы могут обрабатывать взаимодействие между своими собственными двоичными файлами, поэтому у вас есть возможность распространять версию для каждого поддерживаемого компилятора, часто GCC и MSVC. Но в свете этого, большинство библиотек просто экспортируют интерфейс C - и это означает, что указатели являются необработанными.
Небиблиотечный код должен, однако, обычно предпочитать умные указатели необработанным.
источник
Там может быть много причин. Чтобы перечислить несколько из них:
Редактировать : Использование умных указателей - полностью выбор разработчика. Это зависит от различных факторов.
В системах, критичных к производительности, вы можете не использовать интеллектуальные указатели, которые генерируют служебные данные
В проекте, который нуждается в обратной совместимости, вы можете не захотеть использовать умные указатели, которые имеют специфические особенности C ++ 11
Edit2 В течение 24 часов есть ряд отрицательных голосов из-за нижнего прохода. Я не понимаю, почему за этот ответ проголосовали, хотя ниже приведено лишь дополнительное предложение, а не ответ.
Тем не менее, C ++ всегда облегчает вам открывать опции. :) например
И в вашем коде используйте это как:
Для тех, кто говорит, что умный указатель и необработанный указатель разные, я согласен с этим. Приведенный выше код был просто идеей, где можно написать код, который взаимозаменяем только с a
#define
, это не принуждение ;Например,
T*
должен быть удален явно, а умный указатель - нет. Мы можем иметь шаблон,Destroy()
чтобы справиться с этим.и использовать его как:
Таким же образом, для необработанного указателя мы можем скопировать его напрямую, а для умного указателя мы можем использовать специальную операцию.
Где
Assign()
это как:источник
std::auto_ptr
которые долгое время были частью стандарта (и обратите внимание, мне нравитсяstd::auto_ptr
в качестве типа возврата для функций, создающих объекты, даже если это почти бесполезен везде) В C ++ 11std::unique_ptr
нет дополнительных затрат по сравнению с простым указателем.unique_ptr
и исчезновенииauto_ptr
, код, нацеленный на C ++ 03, должен использовать более поздний, в то время как код, нацеленный на C ++ 11, может использовать первый. Умных указателей нетshared_ptr
, есть много стандартных и ни одного стандарта, включая предложения к стандарту, которые были отклонены какmanaged_ptr
unique_ptr
затрат времени выполнения,unique_ptr
безусловно, являются наиболее часто используемыми. Пример кода вы предоставляете также вводит в заблуждение, потому чтоunique_ptr
иT*
это совершенно разные понятия. Тот факт, что вы ссылаетесь на них обоих,type
создает впечатление, что они могут быть заменены друг на друга.С умными указателями есть две проблемы (до C ++ 11):
По умолчанию смарт - указатель, в том , что она является экономически свободным есть
unique_ptr
. К сожалению, это требует семантики перемещения C ++ 11, которая появилась только недавно. Все другие умные указатели имеют стоимость (shared_ptr
,intrusive_ptr
) или имеют менее чем идеальную семантику (auto_ptr
).С C ++ 11 за углом, в результате чего
std::unique_ptr
, можно было бы подумать, что он наконец закончился ... Я не такой оптимистичный.Только несколько крупных компиляторов реализуют большую часть C ++ 11 и только в своих последних версиях. Мы можем ожидать, что основные библиотеки, такие как QT и Boost, будут некоторое время сохранять совместимость с C ++ 03, что несколько препятствует широкому внедрению новых и блестящих интеллектуальных указателей.
источник
Вы не должны держаться подальше от умных указателей, они имеют свое применение, особенно в приложениях, где вы должны передать объект.
Библиотеки обычно либо возвращают значение, либо заполняют объект. У них обычно нет объектов, которые нужно использовать во многих местах, поэтому им не нужно использовать умные указатели (по крайней мере, не в их интерфейсе, они могут использовать их внутри).
Я мог бы взять в качестве примера библиотеку, над которой мы работали, где после нескольких месяцев разработки я понял, что мы использовали указатели и умные указатели только в нескольких классах (3-5% всех классов).
Передачи переменных по ссылке было достаточно в большинстве мест, мы использовали умные указатели всякий раз, когда у нас был объект, который может быть нулевым, и необработанные указатели, когда библиотека, которую мы использовали, заставляла нас.
Редактировать (я не могу комментировать из-за своей репутации): передача переменных по ссылке очень гибкая: если вы хотите, чтобы объект был доступен только для чтения, вы можете использовать константную ссылку (вы все равно можете сделать некоторые неприятные приведения, чтобы иметь возможность писать объект ) но вы получаете максимально возможную защиту (то же самое с умными указателями). Но я согласен, что гораздо приятнее просто вернуть объект.
источник
Qt бессмысленно заново изобрел многие части стандартной библиотеки, пытаясь стать Java. Я считаю, что сейчас у него действительно есть свои умные указатели, но в целом это вряд ли вершина дизайна. Насколько я знаю, wxWidgets был разработан задолго до того, как были написаны полезные умные указатели.
Что касается Boost, я полностью ожидаю, что они используют умные указатели, где это уместно. Возможно, вам придется быть более конкретным.
Кроме того, не забывайте, что существуют умные указатели для обеспечения прав собственности. Если у API нет семантики владения, зачем использовать умный указатель?
источник
QString
, у wxWidgetswxString
, у MFC ужасно названныеCString
. Разве UTF-8 неstd::string
подходит для 99% задач с графическим интерфейсом?Хороший вопрос. Я не знаю конкретных статей, на которые вы ссылаетесь, но я читал подобные вещи время от времени. Я подозреваю, что авторы таких статей склонны склоняться к предвзятому отношению к программированию в стиле C ++. Если писатель программирует на C ++ только тогда, когда он должен, а затем возвращается в Java или тому подобное, как только может, тогда он на самом деле не разделяет мышление C ++.
Можно предположить, что некоторые или большинство авторов пишут о менеджерах памяти для сбора мусора. Я не знаю, но я думаю иначе, чем они.
Умные указатели хороши, но они должны вести подсчет ссылок. Хранение эталонных счетов несет затраты - часто скромные, но, тем не менее, затраты - во время выполнения. Нет ничего плохого в том, чтобы экономить эти затраты, используя голые указатели, особенно если указатели управляются деструкторами.
Одна из замечательных особенностей C ++ - поддержка программирования на встроенных системах. Использование голых указателей является частью этого.
Обновление: Комментатор правильно заметил, что новый C ++
unique_ptr
(доступный с TR1) не считает ссылки. У комментатора также есть другое определение «умного указателя», чем я имею в виду. Он может быть прав насчет определения.Дальнейшее обновление: тема комментариев ниже освещает. Все это рекомендуется к прочтению.
источник
shared_ptr
ведет подсчет ссылок. Существует много других типов интеллектуальных указателей, которые вообще не ведут подсчет ссылок. Наконец, упомянутые библиотеки нацелены на платформы, у которых есть много свободных ресурсов. Не то, чтобы я был downvoter, но все, что я говорю, - то, что Ваш пост полон неправильного.shared_ptr
не имеет накладных расходов. Он имеет накладные расходы только в том случае, если вам не нужна поточно-ориентированная семантика общего владения, что он и обеспечивает.Есть и другие виды умных указателей. Возможно, вам понадобится специальный интеллектуальный указатель для чего-то вроде сетевой репликации (тот, который обнаруживает, если к нему обращаются, и отправляет какие-либо изменения на сервер или что-то подобное), сохраняет историю изменений, отмечает тот факт, что к нему обращались, чтобы его можно было исследовать, когда Вы сохраняете данные на диск и так далее. Не уверен, что делать это в указателе - лучшее решение, но использование встроенных интеллектуальных типов указателей в библиотеках может привести к тому, что люди будут привязаны к ним и потеряют гибкость.
У людей могут быть самые разные требования и решения по управлению памятью, помимо умных указателей. Я мог бы захотеть управлять памятью сам, я мог бы выделить место для вещей в пуле памяти, чтобы он выделялся заранее, а не во время выполнения (полезно для игр). Возможно, я использую реализацию C ++ со сборщиком мусора (C ++ 11 делает это возможным, хотя еще не существует). Или, может быть, я просто не делаю ничего достаточно продвинутого, чтобы беспокоиться о них, я могу знать, что не забуду неинициализированные объекты и так далее. Возможно, я просто уверен в своей способности управлять памятью без использования указателя.
Интеграция с C - еще одна проблема.
Еще одна проблема - умные указатели являются частью STL. C ++ предназначен для использования без STL.
источник
Это также зависит от того, в какой области вы работаете. Я пишу игровые движки для жизни, мы избегаем повышения, как чумы, в играх издержки повышения не приемлемы. В нашем основном движке мы закончили писать свою собственную версию stl (очень похожую на ea stl).
Если бы я написал приложение для форм, я мог бы подумать об использовании умных указателей; но как только управление памятью становится второй натурой, отсутствие детального контроля над памятью становится довольно раздражающим.
источник